X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=blobdiff_plain;f=include%2Fbabeltrace%2Fbitfield-internal.h;fp=include%2Fbabeltrace%2Fbitfield-internal.h;h=5ecde05eb91513e628e5c624f065dc420766527c;hp=c5d5eccdf0d191714d9c53421ad5a97fc6b2599c;hb=7f140ae8b9d8fe9a9df9451ef86eebdbbd62a1f1;hpb=75a151671b0e3d2a90eeff2ccd1ab32d4a1729de diff --git a/include/babeltrace/bitfield-internal.h b/include/babeltrace/bitfield-internal.h index c5d5eccd..5ecde05e 100644 --- a/include/babeltrace/bitfield-internal.h +++ b/include/babeltrace/bitfield-internal.h @@ -2,7 +2,7 @@ #define _BABELTRACE_BITFIELD_H /* - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010-2019 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,49 +27,157 @@ #include /* C99 5.2.4.2 Numerical limits */ #include /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */ -/* 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); \ - \ - for (; sb; sb--) \ - ___v <<= sizeof(___v) * CHAR_BIT - 1; \ - ___v <<= final; \ -}) +/* + * 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 #define _bt_is_signed_type(type) ((type) -1 < (type) 0) /* - * NOTE: The cast to (uint64_t) below ensures that we're not casting a - * negative value, which is undefined in C. However, this limits the - * maximum type size of `type` and `v` to 64-bit. The - * _bt_check_max_64bit() is used to check that the users of this header - * do not use types with a size greater than 64-bit. + * Produce a build-time error if the condition `cond` is non-zero. + * Evaluates as a size_t expression. + */ +#define _BT_BUILD_ASSERT(cond) \ + sizeof(struct { int f:(2 * !!(cond) - 1); }) + +/* + * 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) + +/* + * 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. + * + * 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_unsigned_cast(type, v) \ -({ \ - (sizeof(v) < sizeof(type)) ? \ - ((type) (v)) & ((type) (~(~(uint64_t) 0 << (sizeof(v) * CHAR_BIT)))) : \ - (type) (v); \ -}) +#define _bt_make_mask_complement(type, length) \ + _bt_lshift(_bt_fill_mask(type), length) -#define _bt_check_max_64bit(type) \ - char _max_64bit_assertion[sizeof(type) <= sizeof(uint64_t) ? 1 : -1] __attribute__((unused)) +/* + * 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. + * + * 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, 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. + * + * 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 + +/* + * 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 (; _nr_partial_shifts; _nr_partial_shifts--) \ + (v) = _bt_rshift(v, sizeof(v) * CHAR_BIT - 1); \ + (v) = _bt_rshift(v, _leftover_bits); \ +} while (0) + +/* + * 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 @@ -91,7 +199,7 @@ #define _bt_bitfield_write_le(_ptr, type, _start, _length, _v) \ do { \ - typeof(_v) __v = (_v); \ + __typeof__(_v) __v = (_v); \ type *__ptr = (void *) (_ptr); \ unsigned long __start = (_start), __length = (_length); \ type mask, cmask; \ @@ -108,15 +216,15 @@ do { \ \ /* Trim v high bits */ \ if (__length < sizeof(__v) * CHAR_BIT) \ - __v &= ~((~(typeof(__v)) 0) << __length); \ + __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)); \ + mask = _bt_make_mask(type, __start % ts); \ if (end % ts) \ - mask |= (~(type) 0) << (end % ts); \ - cmask = (type) __v << (__start % 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; \ @@ -124,22 +232,22 @@ do { \ } \ if (__start % ts) { \ cshift = __start % ts; \ - mask = ~((~(type) 0) << cshift); \ - cmask = (type) __v << cshift; \ + mask = _bt_make_mask(type, cshift); \ + cmask = _bt_lshift((type) (__v), cshift); \ cmask &= ~mask; \ __ptr[this_unit] &= mask; \ __ptr[this_unit] |= cmask; \ - __v = _bt_piecewise_rshift(__v, ts - cshift); \ + _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); \ + _bt_safe_rshift(__v, ts); \ __start += ts; \ } \ if (end % ts) { \ - mask = (~(type) 0) << (end % ts); \ + mask = _bt_make_mask_complement(type, end % ts); \ cmask = (type) __v; \ cmask &= ~mask; \ __ptr[this_unit] &= mask; \ @@ -150,7 +258,7 @@ do { \ #define _bt_bitfield_write_be(_ptr, type, _start, _length, _v) \ do { \ - typeof(_v) __v = (_v); \ + __typeof__(_v) __v = (_v); \ type *__ptr = (void *) (_ptr); \ unsigned long __start = (_start), __length = (_length); \ type mask, cmask; \ @@ -167,15 +275,15 @@ do { \ \ /* Trim v high bits */ \ if (__length < sizeof(__v) * CHAR_BIT) \ - __v &= ~((~(typeof(__v)) 0) << __length); \ + __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)); \ + mask = _bt_make_mask(type, (ts - (end % ts)) % ts); \ if (__start % ts) \ - mask |= (~((type) 0)) << (ts - (__start % ts)); \ - cmask = (type) __v << ((ts - (end % ts)) % 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; \ @@ -183,22 +291,22 @@ do { \ } \ if (end % ts) { \ cshift = end % ts; \ - mask = ~((~(type) 0) << (ts - cshift)); \ - cmask = (type) __v << (ts - cshift); \ + mask = _bt_make_mask(type, ts - cshift); \ + cmask = _bt_lshift((type) (__v), ts - cshift); \ cmask &= ~mask; \ __ptr[this_unit] &= mask; \ __ptr[this_unit] |= cmask; \ - __v = _bt_piecewise_rshift(__v, cshift); \ + _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); \ + _bt_safe_rshift(__v, ts); \ end -= ts; \ } \ if (__start % ts) { \ - mask = (~(type) 0) << (ts - (__start % ts)); \ + mask = _bt_make_mask_complement(type, ts - (__start % ts)); \ cmask = (type) __v; \ cmask &= ~mask; \ __ptr[this_unit] &= mask; \ @@ -243,8 +351,8 @@ do { \ #define _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \ do { \ - typeof(*(_vptr)) *__vptr = (_vptr); \ - typeof(*__vptr) __v; \ + __typeof__(*(_vptr)) *__vptr = (_vptr); \ + __typeof__(*__vptr) __v; \ type *__ptr = (void *) (_ptr); \ unsigned long __start = (_start), __length = (_length); \ type mask, cmask; \ @@ -252,10 +360,6 @@ do { \ unsigned long start_unit, end_unit, this_unit; \ unsigned long end, cshift; /* cshift is "complement shift" */ \ \ - { _bt_check_max_64bit(type); } \ - { _bt_check_max_64bit(typeof(*_vptr)); } \ - { _bt_check_max_64bit(typeof(*_ptr)); } \ - \ if (!__length) { \ *__vptr = 0; \ break; \ @@ -266,56 +370,56 @@ do { \ 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; \ + if (_bt_is_signed_type(__typeof__(__v)) \ + && (__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); \ + cmask = _bt_rshift(cmask, __start % ts); \ if ((end - __start) % ts) { \ - mask = ~((~(type) 0) << (end - __start)); \ + mask = _bt_make_mask(type, end - __start); \ cmask &= mask; \ } \ - __v = _bt_piecewise_lshift(__v, end - __start); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + _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); \ + mask = _bt_make_mask(type, cshift); \ cmask = __ptr[this_unit]; \ cmask &= mask; \ - __v = _bt_piecewise_lshift(__v, cshift); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + _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]);\ + _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))); \ + mask = _bt_make_mask(type, ts - (__start % ts)); \ cmask = __ptr[this_unit]; \ - cmask >>= (__start % ts); \ + cmask = _bt_rshift(cmask, __start % ts); \ cmask &= mask; \ - __v = _bt_piecewise_lshift(__v, ts - (__start % ts)); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + _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; \ } while (0) #define _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \ do { \ - typeof(*(_vptr)) *__vptr = (_vptr); \ - typeof(*__vptr) __v; \ + __typeof__(*(_vptr)) *__vptr = (_vptr); \ + __typeof__(*__vptr) __v; \ type *__ptr = (void *) (_ptr); \ unsigned long __start = (_start), __length = (_length); \ type mask, cmask; \ @@ -323,10 +427,6 @@ do { \ unsigned long start_unit, end_unit, this_unit; \ unsigned long end, cshift; /* cshift is "complement shift" */ \ \ - { _bt_check_max_64bit(type); } \ - { _bt_check_max_64bit(typeof(*_vptr)); } \ - { _bt_check_max_64bit(typeof(*_ptr)); } \ - \ if (!__length) { \ *__vptr = 0; \ break; \ @@ -337,48 +437,48 @@ do { \ 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; \ + if (_bt_is_signed_type(__typeof__(__v)) \ + && (__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; \ + cmask = _bt_rshift(cmask, (ts - (end % ts)) % ts); \ if ((end - __start) % ts) { \ - mask = ~((~(type) 0) << (end - __start)); \ + mask = _bt_make_mask(type, end - __start); \ cmask &= mask; \ } \ - __v = _bt_piecewise_lshift(__v, end - __start); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + _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)); \ + mask = _bt_make_mask(type, ts - cshift); \ cmask = __ptr[this_unit]; \ cmask &= mask; \ - __v = _bt_piecewise_lshift(__v, ts - cshift); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + _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]);\ + _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)); \ + mask = _bt_make_mask(type, end % ts); \ cmask = __ptr[this_unit]; \ - cmask >>= ts - (end % ts); \ + cmask = _bt_rshift(cmask, ts - (end % ts)); \ cmask &= mask; \ - __v = _bt_piecewise_lshift(__v, end % ts); \ - __v |= _bt_unsigned_cast(typeof(__v), cmask); \ + _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; \ } while (0)