Commit | Line | Data |
---|---|---|
d79865b9 MD |
1 | #ifndef _BABELTRACE_BITFIELD_H |
2 | #define _BABELTRACE_BITFIELD_H | |
6dc2ca62 MD |
3 | |
4 | /* | |
1d0b2a8b | 5 | * Copyright 2010-2019 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
6dc2ca62 MD |
6 | * |
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | * of this software and associated documentation files (the "Software"), to deal | |
9 | * in the Software without restriction, including without limitation the rights | |
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | * copies of the Software, and to permit persons to whom the Software is | |
12 | * furnished to do so, subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice shall be included in | |
15 | * all copies or substantial portions of the Software. | |
c462e188 MD |
16 | * |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
23 | * SOFTWARE. | |
6dc2ca62 MD |
24 | */ |
25 | ||
26 | #include <stdint.h> /* C99 5.2.4.2 Numerical limits */ | |
3d9990ac | 27 | #include <babeltrace/compat/limits-internal.h> /* C99 5.2.4.2 Numerical limits */ |
3d9990ac | 28 | #include <babeltrace/endian-internal.h> /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */ |
6dc2ca62 | 29 | |
1d0b2a8b MD |
30 | /* |
31 | * This header strictly follows the C99 standard, except for use of the | |
32 | * compiler-specific __typeof__. | |
33 | */ | |
34 | ||
35 | /* | |
36 | * This bitfield header requires the compiler representation of signed | |
37 | * integers to be two's complement. | |
38 | */ | |
39 | #if (-1 != ~0) | |
40 | #error "bitfield.h requires the compiler representation of signed integers to be two's complement." | |
41 | #endif | |
08228826 | 42 | |
cca767be | 43 | #define _bt_is_signed_type(type) ((type) -1 < (type) 0) |
08228826 | 44 | |
a2d16120 | 45 | /* |
1d0b2a8b MD |
46 | * Produce a build-time error if the condition `cond` is non-zero. |
47 | * Evaluates as a size_t expression. | |
48 | */ | |
49 | #define _BT_BUILD_ASSERT(cond) \ | |
50 | sizeof(struct { int f:(2 * !!(cond) - 1); }) | |
51 | ||
52 | /* | |
53 | * Cast value `v` to an unsigned integer of the same size as `v`. | |
54 | */ | |
55 | #define _bt_cast_value_to_unsigned(v) \ | |
56 | (sizeof(v) == sizeof(uint8_t) ? (uint8_t) (v) : \ | |
57 | sizeof(v) == sizeof(uint16_t) ? (uint16_t) (v) : \ | |
58 | sizeof(v) == sizeof(uint32_t) ? (uint32_t) (v) : \ | |
59 | sizeof(v) == sizeof(uint64_t) ? (uint64_t) (v) : \ | |
60 | _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t))) | |
61 | ||
62 | /* | |
63 | * Cast value `v` to an unsigned integer type of the size of type `type` | |
64 | * *without* sign-extension. | |
65 | * | |
66 | * The unsigned cast ensures that we're not shifting a negative value, | |
67 | * which is undefined in C. However, this limits the maximum type size | |
68 | * of `type` to 64-bit. Generate a compile-time error if the size of | |
69 | * `type` is larger than 64-bit. | |
70 | */ | |
71 | #define _bt_cast_value_to_unsigned_type(type, v) \ | |
72 | (sizeof(type) == sizeof(uint8_t) ? \ | |
73 | (uint8_t) _bt_cast_value_to_unsigned(v) : \ | |
74 | sizeof(type) == sizeof(uint16_t) ? \ | |
75 | (uint16_t) _bt_cast_value_to_unsigned(v) : \ | |
76 | sizeof(type) == sizeof(uint32_t) ? \ | |
77 | (uint32_t) _bt_cast_value_to_unsigned(v) : \ | |
78 | sizeof(type) == sizeof(uint64_t) ? \ | |
79 | (uint64_t) _bt_cast_value_to_unsigned(v) : \ | |
80 | _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t))) | |
81 | ||
82 | /* | |
83 | * _bt_fill_mask evaluates to a "type" integer with all bits set. | |
84 | */ | |
85 | #define _bt_fill_mask(type) ((type) ~(type) 0) | |
86 | ||
87 | /* | |
88 | * Left shift a value `v` of `shift` bits. | |
89 | * | |
90 | * The type of `v` can be signed or unsigned integer. | |
91 | * The value of `shift` must be less than the size of `v` (in bits), | |
92 | * otherwise the behavior is undefined. | |
93 | * Evaluates to the result of the shift operation. | |
94 | * | |
95 | * According to the C99 standard, left shift of a left hand-side signed | |
96 | * type is undefined if it has a negative value or if the result cannot | |
97 | * be represented in the result type. This bitfield header discards the | |
98 | * bits that are left-shifted beyond the result type representation, | |
99 | * which is the behavior of an unsigned type left shift operation. | |
100 | * Therefore, always perform left shift on an unsigned type. | |
101 | * | |
102 | * This macro should not be used if `shift` can be greater or equal than | |
103 | * the bitwidth of `v`. See `_bt_safe_lshift`. | |
104 | */ | |
105 | #define _bt_lshift(v, shift) \ | |
106 | ((__typeof__(v)) (_bt_cast_value_to_unsigned(v) << (shift))) | |
107 | ||
108 | /* | |
109 | * Generate a mask of type `type` with the `length` least significant bits | |
110 | * cleared, and the most significant bits set. | |
a2d16120 | 111 | */ |
1d0b2a8b MD |
112 | #define _bt_make_mask_complement(type, length) \ |
113 | _bt_lshift(_bt_fill_mask(type), length) | |
08228826 | 114 | |
1d0b2a8b MD |
115 | /* |
116 | * Generate a mask of type `type` with the `length` least significant bits | |
117 | * set, and the most significant bits cleared. | |
118 | */ | |
119 | #define _bt_make_mask(type, length) \ | |
120 | ((type) ~_bt_make_mask_complement(type, length)) | |
121 | ||
122 | /* | |
123 | * Right shift a value `v` of `shift` bits. | |
124 | * | |
125 | * The type of `v` can be signed or unsigned integer. | |
126 | * The value of `shift` must be less than the size of `v` (in bits), | |
127 | * otherwise the behavior is undefined. | |
128 | * Evaluates to the result of the shift operation. | |
129 | * | |
130 | * According to the C99 standard, right shift of a left hand-side signed | |
131 | * type which has a negative value is implementation defined. This | |
132 | * bitfield header relies on the right shift implementation carrying the | |
133 | * sign bit. If the compiler implementation has a different behavior, | |
134 | * emulate carrying the sign bit. | |
135 | * | |
136 | * This macro should not be used if `shift` can be greater or equal than | |
137 | * the bitwidth of `v`. See `_bt_safe_rshift`. | |
138 | */ | |
139 | #if ((-1 >> 1) == -1) | |
140 | #define _bt_rshift(v, shift) ((v) >> (shift)) | |
141 | #else | |
142 | #define _bt_rshift(v, shift) \ | |
143 | ((__typeof__(v)) ((_bt_cast_value_to_unsigned(v) >> (shift)) | \ | |
144 | ((v) < 0 ? _bt_make_mask_complement(__typeof__(v), \ | |
145 | sizeof(v) * CHAR_BIT - (shift)) : 0))) | |
146 | #endif | |
147 | ||
148 | /* | |
149 | * Right shift a signed or unsigned integer with `shift` value being an | |
150 | * arbitrary number of bits. `v` is modified by this macro. The shift | |
151 | * is transformed into a sequence of `_nr_partial_shifts` consecutive | |
152 | * shift operations, each of a number of bits smaller than the bitwidth | |
153 | * of `v`, ending with a shift of the number of left over bits. | |
154 | */ | |
155 | #define _bt_safe_rshift(v, shift) \ | |
156 | do { \ | |
157 | unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \ | |
158 | unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \ | |
159 | \ | |
160 | for (; _nr_partial_shifts; _nr_partial_shifts--) \ | |
161 | (v) = _bt_rshift(v, sizeof(v) * CHAR_BIT - 1); \ | |
162 | (v) = _bt_rshift(v, _leftover_bits); \ | |
163 | } while (0) | |
164 | ||
165 | /* | |
166 | * Left shift a signed or unsigned integer with `shift` value being an | |
167 | * arbitrary number of bits. `v` is modified by this macro. The shift | |
168 | * is transformed into a sequence of `_nr_partial_shifts` consecutive | |
169 | * shift operations, each of a number of bits smaller than the bitwidth | |
170 | * of `v`, ending with a shift of the number of left over bits. | |
171 | */ | |
172 | #define _bt_safe_lshift(v, shift) \ | |
173 | do { \ | |
174 | unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \ | |
175 | unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \ | |
176 | \ | |
177 | for (; _nr_partial_shifts; _nr_partial_shifts--) \ | |
178 | (v) = _bt_lshift(v, sizeof(v) * CHAR_BIT - 1); \ | |
179 | (v) = _bt_lshift(v, _leftover_bits); \ | |
180 | } while (0) | |
a2d16120 | 181 | |
6dc2ca62 | 182 | /* |
d79865b9 | 183 | * bt_bitfield_write - write integer to a bitfield in native endianness |
6dc2ca62 MD |
184 | * |
185 | * Save integer to the bitfield, which starts at the "start" bit, has "len" | |
186 | * bits. | |
187 | * The inside of a bitfield is from high bits to low bits. | |
188 | * Uses native endianness. | |
189 | * For unsigned "v", pad MSB with 0 if bitfield is larger than v. | |
190 | * For signed "v", sign-extend v if bitfield is larger than v. | |
191 | * | |
192 | * On little endian, bytes are placed from the less significant to the most | |
193 | * significant. Also, consecutive bitfields are placed from lower bits to higher | |
194 | * bits. | |
195 | * | |
196 | * On big endian, bytes are places from most significant to less significant. | |
197 | * Also, consecutive bitfields are placed from higher to lower bits. | |
198 | */ | |
199 | ||
5f61bf21 | 200 | #define _bt_bitfield_write_le(_ptr, type, _start, _length, _v) \ |
6dc2ca62 | 201 | do { \ |
1d0b2a8b | 202 | __typeof__(_v) __v = (_v); \ |
9128428b | 203 | type *__ptr = (void *) (_ptr); \ |
5f61bf21 | 204 | unsigned long __start = (_start), __length = (_length); \ |
47e0f2e2 MD |
205 | type mask, cmask; \ |
206 | unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ | |
6dc2ca62 MD |
207 | unsigned long start_unit, end_unit, this_unit; \ |
208 | unsigned long end, cshift; /* cshift is "complement shift" */ \ | |
6dc2ca62 | 209 | \ |
5f61bf21 | 210 | if (!__length) \ |
6dc2ca62 MD |
211 | break; \ |
212 | \ | |
5f61bf21 MD |
213 | end = __start + __length; \ |
214 | start_unit = __start / ts; \ | |
6dc2ca62 MD |
215 | end_unit = (end + (ts - 1)) / ts; \ |
216 | \ | |
217 | /* Trim v high bits */ \ | |
5f61bf21 | 218 | if (__length < sizeof(__v) * CHAR_BIT) \ |
1d0b2a8b | 219 | __v &= _bt_make_mask(__typeof__(__v), __length); \ |
6dc2ca62 MD |
220 | \ |
221 | /* We can now append v with a simple "or", shift it piece-wise */ \ | |
222 | this_unit = start_unit; \ | |
223 | if (start_unit == end_unit - 1) { \ | |
1d0b2a8b | 224 | mask = _bt_make_mask(type, __start % ts); \ |
6dc2ca62 | 225 | if (end % ts) \ |
1d0b2a8b MD |
226 | mask |= _bt_make_mask_complement(type, end % ts); \ |
227 | cmask = _bt_lshift((type) (__v), __start % ts); \ | |
08228826 | 228 | cmask &= ~mask; \ |
5f61bf21 MD |
229 | __ptr[this_unit] &= mask; \ |
230 | __ptr[this_unit] |= cmask; \ | |
6dc2ca62 MD |
231 | break; \ |
232 | } \ | |
5f61bf21 MD |
233 | if (__start % ts) { \ |
234 | cshift = __start % ts; \ | |
1d0b2a8b MD |
235 | mask = _bt_make_mask(type, cshift); \ |
236 | cmask = _bt_lshift((type) (__v), cshift); \ | |
08228826 | 237 | cmask &= ~mask; \ |
5f61bf21 MD |
238 | __ptr[this_unit] &= mask; \ |
239 | __ptr[this_unit] |= cmask; \ | |
1d0b2a8b | 240 | _bt_safe_rshift(__v, ts - cshift); \ |
5f61bf21 | 241 | __start += ts - cshift; \ |
6dc2ca62 MD |
242 | this_unit++; \ |
243 | } \ | |
244 | for (; this_unit < end_unit - 1; this_unit++) { \ | |
5f61bf21 | 245 | __ptr[this_unit] = (type) __v; \ |
1d0b2a8b | 246 | _bt_safe_rshift(__v, ts); \ |
5f61bf21 | 247 | __start += ts; \ |
6dc2ca62 MD |
248 | } \ |
249 | if (end % ts) { \ | |
1d0b2a8b | 250 | mask = _bt_make_mask_complement(type, end % ts); \ |
5f61bf21 | 251 | cmask = (type) __v; \ |
08228826 | 252 | cmask &= ~mask; \ |
5f61bf21 MD |
253 | __ptr[this_unit] &= mask; \ |
254 | __ptr[this_unit] |= cmask; \ | |
6dc2ca62 | 255 | } else \ |
5f61bf21 | 256 | __ptr[this_unit] = (type) __v; \ |
6dc2ca62 MD |
257 | } while (0) |
258 | ||
5f61bf21 | 259 | #define _bt_bitfield_write_be(_ptr, type, _start, _length, _v) \ |
6dc2ca62 | 260 | do { \ |
1d0b2a8b | 261 | __typeof__(_v) __v = (_v); \ |
9128428b | 262 | type *__ptr = (void *) (_ptr); \ |
5f61bf21 | 263 | unsigned long __start = (_start), __length = (_length); \ |
47e0f2e2 MD |
264 | type mask, cmask; \ |
265 | unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ | |
6dc2ca62 MD |
266 | unsigned long start_unit, end_unit, this_unit; \ |
267 | unsigned long end, cshift; /* cshift is "complement shift" */ \ | |
6dc2ca62 | 268 | \ |
5f61bf21 | 269 | if (!__length) \ |
6dc2ca62 MD |
270 | break; \ |
271 | \ | |
5f61bf21 MD |
272 | end = __start + __length; \ |
273 | start_unit = __start / ts; \ | |
6dc2ca62 MD |
274 | end_unit = (end + (ts - 1)) / ts; \ |
275 | \ | |
276 | /* Trim v high bits */ \ | |
5f61bf21 | 277 | if (__length < sizeof(__v) * CHAR_BIT) \ |
1d0b2a8b | 278 | __v &= _bt_make_mask(__typeof__(__v), __length); \ |
6dc2ca62 MD |
279 | \ |
280 | /* We can now append v with a simple "or", shift it piece-wise */ \ | |
281 | this_unit = end_unit - 1; \ | |
282 | if (start_unit == end_unit - 1) { \ | |
1d0b2a8b | 283 | mask = _bt_make_mask(type, (ts - (end % ts)) % ts); \ |
5f61bf21 | 284 | if (__start % ts) \ |
1d0b2a8b MD |
285 | mask |= _bt_make_mask_complement(type, ts - (__start % ts)); \ |
286 | cmask = _bt_lshift((type) (__v), (ts - (end % ts)) % ts); \ | |
08228826 | 287 | cmask &= ~mask; \ |
5f61bf21 MD |
288 | __ptr[this_unit] &= mask; \ |
289 | __ptr[this_unit] |= cmask; \ | |
6dc2ca62 MD |
290 | break; \ |
291 | } \ | |
292 | if (end % ts) { \ | |
293 | cshift = end % ts; \ | |
1d0b2a8b MD |
294 | mask = _bt_make_mask(type, ts - cshift); \ |
295 | cmask = _bt_lshift((type) (__v), ts - cshift); \ | |
08228826 | 296 | cmask &= ~mask; \ |
5f61bf21 MD |
297 | __ptr[this_unit] &= mask; \ |
298 | __ptr[this_unit] |= cmask; \ | |
1d0b2a8b | 299 | _bt_safe_rshift(__v, cshift); \ |
6dc2ca62 MD |
300 | end -= cshift; \ |
301 | this_unit--; \ | |
302 | } \ | |
08228826 | 303 | for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ |
5f61bf21 | 304 | __ptr[this_unit] = (type) __v; \ |
1d0b2a8b | 305 | _bt_safe_rshift(__v, ts); \ |
6dc2ca62 MD |
306 | end -= ts; \ |
307 | } \ | |
5f61bf21 | 308 | if (__start % ts) { \ |
1d0b2a8b | 309 | mask = _bt_make_mask_complement(type, ts - (__start % ts)); \ |
5f61bf21 | 310 | cmask = (type) __v; \ |
08228826 | 311 | cmask &= ~mask; \ |
5f61bf21 MD |
312 | __ptr[this_unit] &= mask; \ |
313 | __ptr[this_unit] |= cmask; \ | |
6dc2ca62 | 314 | } else \ |
5f61bf21 | 315 | __ptr[this_unit] = (type) __v; \ |
6dc2ca62 MD |
316 | } while (0) |
317 | ||
318 | /* | |
d79865b9 MD |
319 | * bt_bitfield_write - write integer to a bitfield in native endianness |
320 | * bt_bitfield_write_le - write integer to a bitfield in little endian | |
321 | * bt_bitfield_write_be - write integer to a bitfield in big endian | |
6dc2ca62 MD |
322 | */ |
323 | ||
324 | #if (BYTE_ORDER == LITTLE_ENDIAN) | |
325 | ||
47e0f2e2 MD |
326 | #define bt_bitfield_write(ptr, type, _start, _length, _v) \ |
327 | _bt_bitfield_write_le(ptr, type, _start, _length, _v) | |
6dc2ca62 | 328 | |
47e0f2e2 MD |
329 | #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \ |
330 | _bt_bitfield_write_le(ptr, type, _start, _length, _v) | |
a2d16120 | 331 | |
47e0f2e2 MD |
332 | #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \ |
333 | _bt_bitfield_write_be(ptr, unsigned char, _start, _length, _v) | |
6dc2ca62 MD |
334 | |
335 | #elif (BYTE_ORDER == BIG_ENDIAN) | |
336 | ||
47e0f2e2 MD |
337 | #define bt_bitfield_write(ptr, type, _start, _length, _v) \ |
338 | _bt_bitfield_write_be(ptr, type, _start, _length, _v) | |
6dc2ca62 | 339 | |
47e0f2e2 MD |
340 | #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \ |
341 | _bt_bitfield_write_le(ptr, unsigned char, _start, _length, _v) | |
a2d16120 | 342 | |
47e0f2e2 MD |
343 | #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \ |
344 | _bt_bitfield_write_be(ptr, type, _start, _length, _v) | |
6dc2ca62 MD |
345 | |
346 | #else /* (BYTE_ORDER == PDP_ENDIAN) */ | |
347 | ||
348 | #error "Byte order not supported" | |
349 | ||
350 | #endif | |
351 | ||
5f61bf21 | 352 | #define _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ |
6dc2ca62 | 353 | do { \ |
1d0b2a8b MD |
354 | __typeof__(*(_vptr)) *__vptr = (_vptr); \ |
355 | __typeof__(*__vptr) __v; \ | |
9128428b | 356 | type *__ptr = (void *) (_ptr); \ |
5f61bf21 | 357 | unsigned long __start = (_start), __length = (_length); \ |
47e0f2e2 MD |
358 | type mask, cmask; \ |
359 | unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ | |
6dc2ca62 MD |
360 | unsigned long start_unit, end_unit, this_unit; \ |
361 | unsigned long end, cshift; /* cshift is "complement shift" */ \ | |
08228826 | 362 | \ |
5f61bf21 MD |
363 | if (!__length) { \ |
364 | *__vptr = 0; \ | |
08228826 MD |
365 | break; \ |
366 | } \ | |
367 | \ | |
5f61bf21 MD |
368 | end = __start + __length; \ |
369 | start_unit = __start / ts; \ | |
08228826 | 370 | end_unit = (end + (ts - 1)) / ts; \ |
6a7b3345 MD |
371 | \ |
372 | this_unit = end_unit - 1; \ | |
1d0b2a8b MD |
373 | if (_bt_is_signed_type(__typeof__(__v)) \ |
374 | && (__ptr[this_unit] & _bt_lshift((type) 1, (end % ts ? end % ts : ts) - 1))) \ | |
375 | __v = ~(__typeof__(__v)) 0; \ | |
6a7b3345 | 376 | else \ |
5f61bf21 | 377 | __v = 0; \ |
6a7b3345 | 378 | if (start_unit == end_unit - 1) { \ |
5f61bf21 | 379 | cmask = __ptr[this_unit]; \ |
1d0b2a8b | 380 | cmask = _bt_rshift(cmask, __start % ts); \ |
5f61bf21 | 381 | if ((end - __start) % ts) { \ |
1d0b2a8b | 382 | mask = _bt_make_mask(type, end - __start); \ |
6a7b3345 MD |
383 | cmask &= mask; \ |
384 | } \ | |
1d0b2a8b MD |
385 | _bt_safe_lshift(__v, end - __start); \ |
386 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
5f61bf21 | 387 | *__vptr = __v; \ |
6a7b3345 MD |
388 | break; \ |
389 | } \ | |
390 | if (end % ts) { \ | |
391 | cshift = end % ts; \ | |
1d0b2a8b | 392 | mask = _bt_make_mask(type, cshift); \ |
5f61bf21 | 393 | cmask = __ptr[this_unit]; \ |
6a7b3345 | 394 | cmask &= mask; \ |
1d0b2a8b MD |
395 | _bt_safe_lshift(__v, cshift); \ |
396 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
6a7b3345 MD |
397 | end -= cshift; \ |
398 | this_unit--; \ | |
399 | } \ | |
08228826 | 400 | for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ |
1d0b2a8b MD |
401 | _bt_safe_lshift(__v, ts); \ |
402 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), __ptr[this_unit]); \ | |
6a7b3345 MD |
403 | end -= ts; \ |
404 | } \ | |
5f61bf21 | 405 | if (__start % ts) { \ |
1d0b2a8b | 406 | mask = _bt_make_mask(type, ts - (__start % ts)); \ |
5f61bf21 | 407 | cmask = __ptr[this_unit]; \ |
1d0b2a8b | 408 | cmask = _bt_rshift(cmask, __start % ts); \ |
6a7b3345 | 409 | cmask &= mask; \ |
1d0b2a8b MD |
410 | _bt_safe_lshift(__v, ts - (__start % ts)); \ |
411 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
6a7b3345 | 412 | } else { \ |
1d0b2a8b MD |
413 | _bt_safe_lshift(__v, ts); \ |
414 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), __ptr[this_unit]); \ | |
6a7b3345 | 415 | } \ |
5f61bf21 | 416 | *__vptr = __v; \ |
08228826 MD |
417 | } while (0) |
418 | ||
5f61bf21 | 419 | #define _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ |
08228826 | 420 | do { \ |
1d0b2a8b MD |
421 | __typeof__(*(_vptr)) *__vptr = (_vptr); \ |
422 | __typeof__(*__vptr) __v; \ | |
9128428b | 423 | type *__ptr = (void *) (_ptr); \ |
5f61bf21 | 424 | unsigned long __start = (_start), __length = (_length); \ |
47e0f2e2 MD |
425 | type mask, cmask; \ |
426 | unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ | |
08228826 MD |
427 | unsigned long start_unit, end_unit, this_unit; \ |
428 | unsigned long end, cshift; /* cshift is "complement shift" */ \ | |
6dc2ca62 | 429 | \ |
5f61bf21 MD |
430 | if (!__length) { \ |
431 | *__vptr = 0; \ | |
6dc2ca62 | 432 | break; \ |
08228826 | 433 | } \ |
6dc2ca62 | 434 | \ |
5f61bf21 MD |
435 | end = __start + __length; \ |
436 | start_unit = __start / ts; \ | |
6dc2ca62 | 437 | end_unit = (end + (ts - 1)) / ts; \ |
6a7b3345 | 438 | \ |
08228826 | 439 | this_unit = start_unit; \ |
1d0b2a8b MD |
440 | if (_bt_is_signed_type(__typeof__(__v)) \ |
441 | && (__ptr[this_unit] & _bt_lshift((type) 1, ts - (__start % ts) - 1))) \ | |
442 | __v = ~(__typeof__(__v)) 0; \ | |
6a7b3345 | 443 | else \ |
5f61bf21 | 444 | __v = 0; \ |
6a7b3345 | 445 | if (start_unit == end_unit - 1) { \ |
5f61bf21 | 446 | cmask = __ptr[this_unit]; \ |
1d0b2a8b | 447 | cmask = _bt_rshift(cmask, (ts - (end % ts)) % ts); \ |
5f61bf21 | 448 | if ((end - __start) % ts) { \ |
1d0b2a8b | 449 | mask = _bt_make_mask(type, end - __start); \ |
6a7b3345 MD |
450 | cmask &= mask; \ |
451 | } \ | |
1d0b2a8b MD |
452 | _bt_safe_lshift(__v, end - __start); \ |
453 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
5f61bf21 | 454 | *__vptr = __v; \ |
6a7b3345 MD |
455 | break; \ |
456 | } \ | |
5f61bf21 MD |
457 | if (__start % ts) { \ |
458 | cshift = __start % ts; \ | |
1d0b2a8b | 459 | mask = _bt_make_mask(type, ts - cshift); \ |
5f61bf21 | 460 | cmask = __ptr[this_unit]; \ |
6a7b3345 | 461 | cmask &= mask; \ |
1d0b2a8b MD |
462 | _bt_safe_lshift(__v, ts - cshift); \ |
463 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
5f61bf21 | 464 | __start += ts - cshift; \ |
6a7b3345 MD |
465 | this_unit++; \ |
466 | } \ | |
467 | for (; this_unit < end_unit - 1; this_unit++) { \ | |
1d0b2a8b MD |
468 | _bt_safe_lshift(__v, ts); \ |
469 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), __ptr[this_unit]); \ | |
5f61bf21 | 470 | __start += ts; \ |
6a7b3345 MD |
471 | } \ |
472 | if (end % ts) { \ | |
1d0b2a8b | 473 | mask = _bt_make_mask(type, end % ts); \ |
5f61bf21 | 474 | cmask = __ptr[this_unit]; \ |
1d0b2a8b | 475 | cmask = _bt_rshift(cmask, ts - (end % ts)); \ |
6a7b3345 | 476 | cmask &= mask; \ |
1d0b2a8b MD |
477 | _bt_safe_lshift(__v, end % ts); \ |
478 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), cmask); \ | |
6a7b3345 | 479 | } else { \ |
1d0b2a8b MD |
480 | _bt_safe_lshift(__v, ts); \ |
481 | __v |= _bt_cast_value_to_unsigned_type(__typeof__(__v), __ptr[this_unit]); \ | |
6a7b3345 | 482 | } \ |
5f61bf21 | 483 | *__vptr = __v; \ |
6dc2ca62 MD |
484 | } while (0) |
485 | ||
6dc2ca62 | 486 | /* |
d79865b9 MD |
487 | * bt_bitfield_read - read integer from a bitfield in native endianness |
488 | * bt_bitfield_read_le - read integer from a bitfield in little endian | |
489 | * bt_bitfield_read_be - read integer from a bitfield in big endian | |
6dc2ca62 MD |
490 | */ |
491 | ||
08228826 MD |
492 | #if (BYTE_ORDER == LITTLE_ENDIAN) |
493 | ||
5f61bf21 MD |
494 | #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \ |
495 | _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) | |
08228826 | 496 | |
5f61bf21 MD |
497 | #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ |
498 | _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) | |
a2d16120 | 499 | |
5f61bf21 MD |
500 | #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ |
501 | _bt_bitfield_read_be(_ptr, unsigned char, _start, _length, _vptr) | |
08228826 MD |
502 | |
503 | #elif (BYTE_ORDER == BIG_ENDIAN) | |
504 | ||
5f61bf21 MD |
505 | #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \ |
506 | _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) | |
08228826 | 507 | |
5f61bf21 MD |
508 | #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ |
509 | _bt_bitfield_read_le(_ptr, unsigned char, _start, _length, _vptr) | |
a2d16120 | 510 | |
5f61bf21 MD |
511 | #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ |
512 | _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) | |
08228826 MD |
513 | |
514 | #else /* (BYTE_ORDER == PDP_ENDIAN) */ | |
515 | ||
516 | #error "Byte order not supported" | |
517 | ||
518 | #endif | |
6dc2ca62 | 519 | |
d79865b9 | 520 | #endif /* _BABELTRACE_BITFIELD_H */ |