X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=include%2Flttng%2Fbitfield.h;h=e628af39ca9cdf7d4004769014d52768fb6810e2;hb=c0c0989ab70574e09b2f7e8b48c2da6af664a849;hp=df8ab0b2b67a224bed60a9b86d866494a288f37f;hpb=4318ae1be57eb7983ab4857a7a8eeb4a030a8216;p=lttng-ust.git diff --git a/include/lttng/bitfield.h b/include/lttng/bitfield.h index df8ab0b2..e628af39 100644 --- a/include/lttng/bitfield.h +++ b/include/lttng/bitfield.h @@ -1,62 +1,195 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (C) 2010-2019 Mathieu Desnoyers + */ + #ifndef _BABELTRACE_BITFIELD_H #define _BABELTRACE_BITFIELD_H +#include /* C99 5.2.4.2 Numerical limits */ +#include /* C99 5.2.4.2 Numerical limits */ +#include /* C99 7.16 bool type */ +#include /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */ + +/* + * This header strictly follows the C99 standard, except for use of the + * compiler-specific __typeof__. + */ + +/* + * This bitfield header requires the compiler representation of signed + * integers to be two's complement. + */ +#if (-1 != ~0) +#error "bitfield.h requires the compiler representation of signed integers to be two's complement." +#endif + +/* + * _bt_is_signed_type() willingly generates comparison of unsigned + * expression < 0, which is always false. Silence compiler warnings. + * GCC versions lower than 4.6.0 do not accept diagnostic pragma inside + * functions. + */ +#if defined (__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40600 +# define _BT_DIAG_PUSH _Pragma("GCC diagnostic push") +# define _BT_DIAG_POP _Pragma("GCC diagnostic pop") + +# define _BT_DIAG_STRINGIFY_1(x) #x +# define _BT_DIAG_STRINGIFY(x) _BT_DIAG_STRINGIFY_1(x) + +# define _BT_DIAG_IGNORE(option) \ + _Pragma(_BT_DIAG_STRINGIFY(GCC diagnostic ignored option)) +# define _BT_DIAG_IGNORE_TYPE_LIMITS _BT_DIAG_IGNORE("-Wtype-limits") +#else +# define _BT_DIAG_PUSH +# define _BT_DIAG_POP +# define _BT_DIAG_IGNORE +# define _BT_DIAG_IGNORE_TYPE_LIMITS +#endif + +#define _bt_is_signed_type(type) ((type) -1 < (type) 0) + +/* + * Produce a build-time error if the condition `cond` is non-zero. + * Evaluates as a size_t expression. + */ +#ifdef __cplusplus +#define _BT_BUILD_ASSERT(cond) ([]{static_assert((cond), "");}, 0) +#else +#define _BT_BUILD_ASSERT(cond) \ + sizeof(struct { int f:(2 * !!(cond) - 1); }) +#endif + +/* + * Cast value `v` to an unsigned integer of the same size as `v`. + */ +#define _bt_cast_value_to_unsigned(v) \ + (sizeof(v) == sizeof(uint8_t) ? (uint8_t) (v) : \ + sizeof(v) == sizeof(uint16_t) ? (uint16_t) (v) : \ + sizeof(v) == sizeof(uint32_t) ? (uint32_t) (v) : \ + sizeof(v) == sizeof(uint64_t) ? (uint64_t) (v) : \ + _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t))) + +/* + * Cast value `v` to an unsigned integer type of the size of type `type` + * *without* sign-extension. + * + * The unsigned cast ensures that we're not shifting a negative value, + * which is undefined in C. However, this limits the maximum type size + * of `type` to 64-bit. Generate a compile-time error if the size of + * `type` is larger than 64-bit. + */ +#define _bt_cast_value_to_unsigned_type(type, v) \ + (sizeof(type) == sizeof(uint8_t) ? \ + (uint8_t) _bt_cast_value_to_unsigned(v) : \ + sizeof(type) == sizeof(uint16_t) ? \ + (uint16_t) _bt_cast_value_to_unsigned(v) : \ + sizeof(type) == sizeof(uint32_t) ? \ + (uint32_t) _bt_cast_value_to_unsigned(v) : \ + sizeof(type) == sizeof(uint64_t) ? \ + (uint64_t) _bt_cast_value_to_unsigned(v) : \ + _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t))) + +/* + * _bt_fill_mask evaluates to a "type" integer with all bits set. + */ +#define _bt_fill_mask(type) ((type) ~(type) 0) + /* - * BabelTrace + * Left shift a value `v` of `shift` bits. + * + * The type of `v` can be signed or unsigned integer. + * The value of `shift` must be less than the size of `v` (in bits), + * otherwise the behavior is undefined. + * Evaluates to the result of the shift operation. + * + * According to the C99 standard, left shift of a left hand-side signed + * type is undefined if it has a negative value or if the result cannot + * be represented in the result type. This bitfield header discards the + * bits that are left-shifted beyond the result type representation, + * which is the behavior of an unsigned type left shift operation. + * Therefore, always perform left shift on an unsigned type. * - * Bitfields read/write functions. + * This macro should not be used if `shift` can be greater or equal than + * the bitwidth of `v`. See `_bt_safe_lshift`. + */ +#define _bt_lshift(v, shift) \ + ((__typeof__(v)) (_bt_cast_value_to_unsigned(v) << (shift))) + +/* + * Generate a mask of type `type` with the `length` least significant bits + * cleared, and the most significant bits set. + */ +#define _bt_make_mask_complement(type, length) \ + _bt_lshift(_bt_fill_mask(type), length) + +/* + * Generate a mask of type `type` with the `length` least significant bits + * set, and the most significant bits cleared. + */ +#define _bt_make_mask(type, length) \ + ((type) ~_bt_make_mask_complement(type, length)) + +/* + * Right shift a value `v` of `shift` bits. * - * Copyright 2010 - Mathieu Desnoyers + * The type of `v` can be signed or unsigned integer. + * The value of `shift` must be less than the size of `v` (in bits), + * otherwise the behavior is undefined. + * Evaluates to the result of the shift operation. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * According to the C99 standard, right shift of a left hand-side signed + * type which has a negative value is implementation defined. This + * bitfield header relies on the right shift implementation carrying the + * sign bit. If the compiler implementation has a different behavior, + * emulate carrying the sign bit. * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * This macro should not be used if `shift` can be greater or equal than + * the bitwidth of `v`. See `_bt_safe_rshift`. */ +#if ((-1 >> 1) == -1) +#define _bt_rshift(v, shift) ((v) >> (shift)) +#else +#define _bt_rshift(v, shift) \ + ((__typeof__(v)) ((_bt_cast_value_to_unsigned(v) >> (shift)) | \ + ((v) < 0 ? _bt_make_mask_complement(__typeof__(v), \ + sizeof(v) * CHAR_BIT - (shift)) : 0))) +#endif -#include /* C99 5.2.4.2 Numerical limits */ -#include /* C99 5.2.4.2 Numerical limits */ -#include /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */ -#include - -/* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */ -#define _bt_piecewise_rshift(_v, _shift) \ -({ \ - typeof(_v) ___v = (_v); \ - typeof(_shift) ___shift = (_shift); \ - unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \ - unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \ - \ - for (; sb; sb--) \ - ___v >>= sizeof(___v) * CHAR_BIT - 1; \ - ___v >>= final; \ -}) - -#define _bt_piecewise_lshift(_v, _shift) \ -({ \ - typeof(_v) ___v = (_v); \ - typeof(_shift) ___shift = (_shift); \ - unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \ - unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \ +/* + * Right shift a signed or unsigned integer with `shift` value being an + * arbitrary number of bits. `v` is modified by this macro. The shift + * is transformed into a sequence of `_nr_partial_shifts` consecutive + * shift operations, each of a number of bits smaller than the bitwidth + * of `v`, ending with a shift of the number of left over bits. + */ +#define _bt_safe_rshift(v, shift) \ +do { \ + unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \ + unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \ \ - for (; sb; sb--) \ - ___v <<= sizeof(___v) * CHAR_BIT - 1; \ - ___v <<= final; \ -}) - -#define _bt_is_signed_type(type) (((type)(-1)) < 0) + for (; _nr_partial_shifts; _nr_partial_shifts--) \ + (v) = _bt_rshift(v, sizeof(v) * CHAR_BIT - 1); \ + (v) = _bt_rshift(v, _leftover_bits); \ +} while (0) -#define _bt_unsigned_cast(type, v) \ -({ \ - (sizeof(v) < sizeof(type)) ? \ - ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \ - (type) (v); \ -}) +/* + * Left shift a signed or unsigned integer with `shift` value being an + * arbitrary number of bits. `v` is modified by this macro. The shift + * is transformed into a sequence of `_nr_partial_shifts` consecutive + * shift operations, each of a number of bits smaller than the bitwidth + * of `v`, ending with a shift of the number of left over bits. + */ +#define _bt_safe_lshift(v, shift) \ +do { \ + unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \ + unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \ + \ + for (; _nr_partial_shifts; _nr_partial_shifts--) \ + (v) = _bt_lshift(v, sizeof(v) * CHAR_BIT - 1); \ + (v) = _bt_lshift(v, _leftover_bits); \ +} while (0) /* * bt_bitfield_write - write integer to a bitfield in native endianness @@ -76,122 +209,122 @@ * Also, consecutive bitfields are placed from higher to lower bits. */ -#define _bt_bitfield_write_le(_ptr, type, _start, _length, _v) \ +#define _bt_bitfield_write_le(ptr, type, start, length, v) \ do { \ - typeof(_v) __v = (_v); \ - type *__ptr = (void *) (_ptr); \ - unsigned long __start = (_start), __length = (_length); \ - type mask, cmask; \ - unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ - unsigned long start_unit, end_unit, this_unit; \ - unsigned long end, cshift; /* cshift is "complement shift" */ \ + __typeof__(v) _v = (v); \ + type *_ptr = (void *) (ptr); \ + unsigned long _start = (start), _length = (length); \ + type _mask, _cmask; \ + unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long _start_unit, _end_unit, _this_unit; \ + unsigned long _end, _cshift; /* _cshift is "complement shift" */ \ \ - if (!__length) \ + if (!_length) \ break; \ \ - end = __start + __length; \ - start_unit = __start / ts; \ - end_unit = (end + (ts - 1)) / ts; \ + _end = _start + _length; \ + _start_unit = _start / _ts; \ + _end_unit = (_end + (_ts - 1)) / _ts; \ \ /* Trim v high bits */ \ - if (__length < sizeof(__v) * CHAR_BIT) \ - __v &= ~((~(typeof(__v)) 0) << __length); \ + if (_length < sizeof(_v) * CHAR_BIT) \ + _v &= _bt_make_mask(__typeof__(_v), _length); \ \ /* We can now append v with a simple "or", shift it piece-wise */ \ - this_unit = start_unit; \ - if (start_unit == end_unit - 1) { \ - mask = ~((~(type) 0) << (__start % ts)); \ - if (end % ts) \ - mask |= (~(type) 0) << (end % ts); \ - cmask = (type) __v << (__start % ts); \ - cmask &= ~mask; \ - __ptr[this_unit] &= mask; \ - __ptr[this_unit] |= cmask; \ + _this_unit = _start_unit; \ + if (_start_unit == _end_unit - 1) { \ + _mask = _bt_make_mask(type, _start % _ts); \ + if (_end % _ts) \ + _mask |= _bt_make_mask_complement(type, _end % _ts); \ + _cmask = _bt_lshift((type) (_v), _start % _ts); \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ break; \ } \ - if (__start % ts) { \ - cshift = __start % ts; \ - mask = ~((~(type) 0) << cshift); \ - cmask = (type) __v << cshift; \ - cmask &= ~mask; \ - __ptr[this_unit] &= mask; \ - __ptr[this_unit] |= cmask; \ - __v = _bt_piecewise_rshift(__v, ts - cshift); \ - __start += ts - cshift; \ - this_unit++; \ + if (_start % _ts) { \ + _cshift = _start % _ts; \ + _mask = _bt_make_mask(type, _cshift); \ + _cmask = _bt_lshift((type) (_v), _cshift); \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ + _bt_safe_rshift(_v, _ts - _cshift); \ + _start += _ts - _cshift; \ + _this_unit++; \ } \ - for (; this_unit < end_unit - 1; this_unit++) { \ - __ptr[this_unit] = (type) __v; \ - __v = _bt_piecewise_rshift(__v, ts); \ - __start += ts; \ + for (; _this_unit < _end_unit - 1; _this_unit++) { \ + _ptr[_this_unit] = (type) _v; \ + _bt_safe_rshift(_v, _ts); \ + _start += _ts; \ } \ - if (end % ts) { \ - mask = (~(type) 0) << (end % ts); \ - cmask = (type) __v; \ - cmask &= ~mask; \ - __ptr[this_unit] &= mask; \ - __ptr[this_unit] |= cmask; \ + if (_end % _ts) { \ + _mask = _bt_make_mask_complement(type, _end % _ts); \ + _cmask = (type) _v; \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ } else \ - __ptr[this_unit] = (type) __v; \ + _ptr[_this_unit] = (type) _v; \ } while (0) -#define _bt_bitfield_write_be(_ptr, type, _start, _length, _v) \ +#define _bt_bitfield_write_be(ptr, type, start, length, v) \ do { \ - typeof(_v) __v = (_v); \ - type *__ptr = (void *) (_ptr); \ - unsigned long __start = (_start), __length = (_length); \ - type mask, cmask; \ - unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ - unsigned long start_unit, end_unit, this_unit; \ - unsigned long end, cshift; /* cshift is "complement shift" */ \ + __typeof__(v) _v = (v); \ + type *_ptr = (void *) (ptr); \ + unsigned long _start = (start), _length = (length); \ + type _mask, _cmask; \ + unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long _start_unit, _end_unit, _this_unit; \ + unsigned long _end, _cshift; /* _cshift is "complement shift" */ \ \ - if (!__length) \ + if (!_length) \ break; \ \ - end = __start + __length; \ - start_unit = __start / ts; \ - end_unit = (end + (ts - 1)) / ts; \ + _end = _start + _length; \ + _start_unit = _start / _ts; \ + _end_unit = (_end + (_ts - 1)) / _ts; \ \ /* Trim v high bits */ \ - if (__length < sizeof(__v) * CHAR_BIT) \ - __v &= ~((~(typeof(__v)) 0) << __length); \ + if (_length < sizeof(_v) * CHAR_BIT) \ + _v &= _bt_make_mask(__typeof__(_v), _length); \ \ /* We can now append v with a simple "or", shift it piece-wise */ \ - this_unit = end_unit - 1; \ - if (start_unit == end_unit - 1) { \ - mask = ~((~(type) 0) << ((ts - (end % ts)) % ts)); \ - if (__start % ts) \ - mask |= (~((type) 0)) << (ts - (__start % ts)); \ - cmask = (type) __v << ((ts - (end % ts)) % ts); \ - cmask &= ~mask; \ - __ptr[this_unit] &= mask; \ - __ptr[this_unit] |= cmask; \ + _this_unit = _end_unit - 1; \ + if (_start_unit == _end_unit - 1) { \ + _mask = _bt_make_mask(type, (_ts - (_end % _ts)) % _ts); \ + if (_start % _ts) \ + _mask |= _bt_make_mask_complement(type, _ts - (_start % _ts)); \ + _cmask = _bt_lshift((type) (_v), (_ts - (_end % _ts)) % _ts); \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ break; \ } \ - if (end % ts) { \ - cshift = end % ts; \ - mask = ~((~(type) 0) << (ts - cshift)); \ - cmask = (type) __v << (ts - cshift); \ - cmask &= ~mask; \ - __ptr[this_unit] &= mask; \ - __ptr[this_unit] |= cmask; \ - __v = _bt_piecewise_rshift(__v, cshift); \ - end -= cshift; \ - this_unit--; \ + if (_end % _ts) { \ + _cshift = _end % _ts; \ + _mask = _bt_make_mask(type, _ts - _cshift); \ + _cmask = _bt_lshift((type) (_v), _ts - _cshift); \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ + _bt_safe_rshift(_v, _cshift); \ + _end -= _cshift; \ + _this_unit--; \ } \ - for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ - __ptr[this_unit] = (type) __v; \ - __v = _bt_piecewise_rshift(__v, ts); \ - end -= ts; \ + for (; (long) _this_unit >= (long) _start_unit + 1; _this_unit--) { \ + _ptr[_this_unit] = (type) _v; \ + _bt_safe_rshift(_v, _ts); \ + _end -= _ts; \ } \ - if (__start % ts) { \ - mask = (~(type) 0) << (ts - (__start % ts)); \ - cmask = (type) __v; \ - cmask &= ~mask; \ - __ptr[this_unit] &= mask; \ - __ptr[this_unit] |= cmask; \ + if (_start % _ts) { \ + _mask = _bt_make_mask_complement(type, _ts - (_start % _ts)); \ + _cmask = (type) _v; \ + _cmask &= ~_mask; \ + _ptr[_this_unit] &= _mask; \ + _ptr[_this_unit] |= _cmask; \ } else \ - __ptr[this_unit] = (type) __v; \ + _ptr[_this_unit] = (type) _v; \ } while (0) /* @@ -202,25 +335,25 @@ do { \ #if (BYTE_ORDER == LITTLE_ENDIAN) -#define bt_bitfield_write(ptr, type, _start, _length, _v) \ - _bt_bitfield_write_le(ptr, type, _start, _length, _v) +#define bt_bitfield_write(ptr, type, start, length, v) \ + _bt_bitfield_write_le(ptr, type, start, length, v) + +#define bt_bitfield_write_le(ptr, type, start, length, v) \ + _bt_bitfield_write_le(ptr, type, start, length, v) -#define bt_bitfield_write_le(ptr, type, _start, _length, _v) \ - _bt_bitfield_write_le(ptr, type, _start, _length, _v) - -#define bt_bitfield_write_be(ptr, type, _start, _length, _v) \ - _bt_bitfield_write_be(ptr, unsigned char, _start, _length, _v) +#define bt_bitfield_write_be(ptr, type, start, length, v) \ + _bt_bitfield_write_be(ptr, unsigned char, start, length, v) #elif (BYTE_ORDER == BIG_ENDIAN) -#define bt_bitfield_write(ptr, type, _start, _length, _v) \ - _bt_bitfield_write_be(ptr, type, _start, _length, _v) +#define bt_bitfield_write(ptr, type, start, length, v) \ + _bt_bitfield_write_be(ptr, type, start, length, v) -#define bt_bitfield_write_le(ptr, type, _start, _length, _v) \ - _bt_bitfield_write_le(ptr, unsigned char, _start, _length, _v) - -#define bt_bitfield_write_be(ptr, type, _start, _length, _v) \ - _bt_bitfield_write_be(ptr, type, _start, _length, _v) +#define bt_bitfield_write_le(ptr, type, start, length, v) \ + _bt_bitfield_write_le(ptr, unsigned char, start, length, v) + +#define bt_bitfield_write_be(ptr, type, start, length, v) \ + _bt_bitfield_write_be(ptr, type, start, length, v) #else /* (BYTE_ORDER == PDP_ENDIAN) */ @@ -228,138 +361,148 @@ do { \ #endif -#define _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ +#define _bt_bitfield_read_le(ptr, type, start, length, vptr) \ do { \ - typeof(*(_vptr)) *__vptr = (_vptr); \ - typeof(*__vptr) __v; \ - type *__ptr = (void *) (_ptr); \ - unsigned long __start = (_start), __length = (_length); \ - type mask, cmask; \ - unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ - unsigned long start_unit, end_unit, this_unit; \ - unsigned long end, cshift; /* cshift is "complement shift" */ \ + __typeof__(*(vptr)) *_vptr = (vptr); \ + __typeof__(*_vptr) _v; \ + type *_ptr = (type *) (ptr); \ + unsigned long _start = (start), _length = (length); \ + type _mask, _cmask; \ + unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long _start_unit, _end_unit, _this_unit; \ + unsigned long _end, _cshift; /* _cshift is "complement shift" */ \ + bool _is_signed_type; \ \ - if (!__length) { \ - *__vptr = 0; \ + if (!_length) { \ + *_vptr = 0; \ break; \ } \ \ - end = __start + __length; \ - start_unit = __start / ts; \ - end_unit = (end + (ts - 1)) / ts; \ + _end = _start + _length; \ + _start_unit = _start / _ts; \ + _end_unit = (_end + (_ts - 1)) / _ts; \ \ - this_unit = end_unit - 1; \ - if (_bt_is_signed_type(typeof(__v)) \ - && (__ptr[this_unit] & ((type) 1 << ((end % ts ? : ts) - 1)))) \ - __v = ~(typeof(__v)) 0; \ + _this_unit = _end_unit - 1; \ + _BT_DIAG_PUSH \ + _BT_DIAG_IGNORE_TYPE_LIMITS \ + _is_signed_type = _bt_is_signed_type(__typeof__(_v)); \ + _BT_DIAG_POP \ + if (_is_signed_type \ + && (_ptr[_this_unit] & _bt_lshift((type) 1, (_end % _ts ? _end % _ts : _ts) - 1))) \ + _v = ~(__typeof__(_v)) 0; \ else \ - __v = 0; \ - if (start_unit == end_unit - 1) { \ - cmask = __ptr[this_unit]; \ - cmask >>= (__start % ts); \ - if ((end - __start) % ts) { \ - mask = ~((~(type) 0) << (end - __start)); \ - cmask &= mask; \ + _v = 0; \ + if (_start_unit == _end_unit - 1) { \ + _cmask = _ptr[_this_unit]; \ + _cmask = _bt_rshift(_cmask, _start % _ts); \ + if ((_end - _start) % _ts) { \ + _mask = _bt_make_mask(type, _end - _start); \ + _cmask &= _mask; \ } \ - __v = _bt_piecewise_lshift(__v, end - __start); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ - *__vptr = __v; \ + _bt_safe_lshift(_v, _end - _start); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ + *_vptr = _v; \ break; \ } \ - if (end % ts) { \ - cshift = end % ts; \ - mask = ~((~(type) 0) << cshift); \ - cmask = __ptr[this_unit]; \ - cmask &= mask; \ - __v = _bt_piecewise_lshift(__v, cshift); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ - end -= cshift; \ - this_unit--; \ + if (_end % _ts) { \ + _cshift = _end % _ts; \ + _mask = _bt_make_mask(type, _cshift); \ + _cmask = _ptr[_this_unit]; \ + _cmask &= _mask; \ + _bt_safe_lshift(_v, _cshift); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ + _end -= _cshift; \ + _this_unit--; \ } \ - for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ - __v = _bt_piecewise_lshift(__v, ts); \ - __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\ - end -= ts; \ + for (; (long) _this_unit >= (long) _start_unit + 1; _this_unit--) { \ + _bt_safe_lshift(_v, _ts); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \ + _end -= _ts; \ } \ - if (__start % ts) { \ - mask = ~((~(type) 0) << (ts - (__start % ts))); \ - cmask = __ptr[this_unit]; \ - cmask >>= (__start % ts); \ - cmask &= mask; \ - __v = _bt_piecewise_lshift(__v, ts - (__start % ts)); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + if (_start % _ts) { \ + _mask = _bt_make_mask(type, _ts - (_start % _ts)); \ + _cmask = _ptr[_this_unit]; \ + _cmask = _bt_rshift(_cmask, _start % _ts); \ + _cmask &= _mask; \ + _bt_safe_lshift(_v, _ts - (_start % _ts)); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ } else { \ - __v = _bt_piecewise_lshift(__v, ts); \ - __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\ + _bt_safe_lshift(_v, _ts); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \ } \ - *__vptr = __v; \ + *_vptr = _v; \ } while (0) -#define _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ +#define _bt_bitfield_read_be(ptr, type, start, length, vptr) \ do { \ - typeof(*(_vptr)) *__vptr = (_vptr); \ - typeof(*__vptr) __v; \ - type *__ptr = (void *) (_ptr); \ - unsigned long __start = (_start), __length = (_length); \ - type mask, cmask; \ - unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \ - unsigned long start_unit, end_unit, this_unit; \ - unsigned long end, cshift; /* cshift is "complement shift" */ \ + __typeof__(*(vptr)) *_vptr = (vptr); \ + __typeof__(*_vptr) _v; \ + type *_ptr = (void *) (ptr); \ + unsigned long _start = (start), _length = (length); \ + type _mask, _cmask; \ + unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */ \ + unsigned long _start_unit, _end_unit, _this_unit; \ + unsigned long _end, _cshift; /* _cshift is "complement shift" */ \ + bool _is_signed_type; \ \ - if (!__length) { \ - *__vptr = 0; \ + if (!_length) { \ + *_vptr = 0; \ break; \ } \ \ - end = __start + __length; \ - start_unit = __start / ts; \ - end_unit = (end + (ts - 1)) / ts; \ + _end = _start + _length; \ + _start_unit = _start / _ts; \ + _end_unit = (_end + (_ts - 1)) / _ts; \ \ - this_unit = start_unit; \ - if (_bt_is_signed_type(typeof(__v)) \ - && (__ptr[this_unit] & ((type) 1 << (ts - (__start % ts) - 1)))) \ - __v = ~(typeof(__v)) 0; \ + _this_unit = _start_unit; \ + _BT_DIAG_PUSH \ + _BT_DIAG_IGNORE_TYPE_LIMITS \ + _is_signed_type = _bt_is_signed_type(__typeof__(_v)); \ + _BT_DIAG_POP \ + if (_is_signed_type \ + && (_ptr[_this_unit] & _bt_lshift((type) 1, _ts - (_start % _ts) - 1))) \ + _v = ~(__typeof__(_v)) 0; \ else \ - __v = 0; \ - if (start_unit == end_unit - 1) { \ - cmask = __ptr[this_unit]; \ - cmask >>= (ts - (end % ts)) % ts; \ - if ((end - __start) % ts) { \ - mask = ~((~(type) 0) << (end - __start)); \ - cmask &= mask; \ + _v = 0; \ + if (_start_unit == _end_unit - 1) { \ + _cmask = _ptr[_this_unit]; \ + _cmask = _bt_rshift(_cmask, (_ts - (_end % _ts)) % _ts); \ + if ((_end - _start) % _ts) { \ + _mask = _bt_make_mask(type, _end - _start); \ + _cmask &= _mask; \ } \ - __v = _bt_piecewise_lshift(__v, end - __start); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ - *__vptr = __v; \ + _bt_safe_lshift(_v, _end - _start); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ + *_vptr = _v; \ break; \ } \ - if (__start % ts) { \ - cshift = __start % ts; \ - mask = ~((~(type) 0) << (ts - cshift)); \ - cmask = __ptr[this_unit]; \ - cmask &= mask; \ - __v = _bt_piecewise_lshift(__v, ts - cshift); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ - __start += ts - cshift; \ - this_unit++; \ + if (_start % _ts) { \ + _cshift = _start % _ts; \ + _mask = _bt_make_mask(type, _ts - _cshift); \ + _cmask = _ptr[_this_unit]; \ + _cmask &= _mask; \ + _bt_safe_lshift(_v, _ts - _cshift); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ + _start += _ts - _cshift; \ + _this_unit++; \ } \ - for (; this_unit < end_unit - 1; this_unit++) { \ - __v = _bt_piecewise_lshift(__v, ts); \ - __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\ - __start += ts; \ + for (; _this_unit < _end_unit - 1; _this_unit++) { \ + _bt_safe_lshift(_v, _ts); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \ + _start += _ts; \ } \ - if (end % ts) { \ - mask = ~((~(type) 0) << (end % ts)); \ - cmask = __ptr[this_unit]; \ - cmask >>= ts - (end % ts); \ - cmask &= mask; \ - __v = _bt_piecewise_lshift(__v, end % ts); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + if (_end % _ts) { \ + _mask = _bt_make_mask(type, _end % _ts); \ + _cmask = _ptr[_this_unit]; \ + _cmask = _bt_rshift(_cmask, _ts - (_end % _ts)); \ + _cmask &= _mask; \ + _bt_safe_lshift(_v, _end % _ts); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \ } else { \ - __v = _bt_piecewise_lshift(__v, ts); \ - __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\ + _bt_safe_lshift(_v, _ts); \ + _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \ } \ - *__vptr = __v; \ + *_vptr = _v; \ } while (0) /* @@ -370,25 +513,25 @@ do { \ #if (BYTE_ORDER == LITTLE_ENDIAN) -#define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \ - _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) +#define bt_bitfield_read(ptr, type, start, length, vptr) \ + _bt_bitfield_read_le(ptr, type, start, length, vptr) + +#define bt_bitfield_read_le(ptr, type, start, length, vptr) \ + _bt_bitfield_read_le(ptr, type, start, length, vptr) -#define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ - _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) - -#define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ - _bt_bitfield_read_be(_ptr, unsigned char, _start, _length, _vptr) +#define bt_bitfield_read_be(ptr, type, start, length, vptr) \ + _bt_bitfield_read_be(ptr, unsigned char, start, length, vptr) #elif (BYTE_ORDER == BIG_ENDIAN) -#define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \ - _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) +#define bt_bitfield_read(ptr, type, start, length, vptr) \ + _bt_bitfield_read_be(ptr, type, start, length, vptr) + +#define bt_bitfield_read_le(ptr, type, start, length, vptr) \ + _bt_bitfield_read_le(ptr, unsigned char, start, length, vptr) -#define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ - _bt_bitfield_read_le(_ptr, unsigned char, _start, _length, _vptr) - -#define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ - _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) +#define bt_bitfield_read_be(ptr, type, start, length, vptr) \ + _bt_bitfield_read_be(ptr, type, start, length, vptr) #else /* (BYTE_ORDER == PDP_ENDIAN) */