From: Mathieu Desnoyers Date: Mon, 27 Sep 2010 17:55:26 +0000 (-0400) Subject: Bitfields: allow per-word read on native endianness X-Git-Tag: v0.1~243 X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=0822882635143b2de9b1d9488cb8b24f2a6d90a2 Bitfields: allow per-word read on native endianness Signed-off-by: Mathieu Desnoyers --- diff --git a/include/ctf/bitfield.h b/include/ctf/bitfield.h index 1cf7c1a2..ba153251 100644 --- a/include/ctf/bitfield.h +++ b/include/ctf/bitfield.h @@ -24,7 +24,7 @@ #include /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */ #include -/* We can't shift a int from 32 bit, >> 32 on int is undefined */ +/* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */ #define _ctf_piecewise_rshift(v, shift) \ ({ \ unsigned long sb = (shift) / (sizeof(v) * CHAR_BIT - 1); \ @@ -36,6 +36,26 @@ _v >>= final; \ }) +#define _ctf_piecewise_lshift(v, shift) \ +({ \ + unsigned long sb = (shift) / (sizeof(v) * CHAR_BIT - 1); \ + unsigned long final = (shift) % (sizeof(v) * CHAR_BIT - 1); \ + typeof(v) _v = (v); \ + \ + for (; sb; sb--) \ + _v <<= sizeof(v) * CHAR_BIT - 1; \ + _v <<= final; \ +}) + +#define _ctf_is_signed_type(type) (((type)(-1)) < 0) + +#define _ctf_unsigned_cast(type, v) \ +({ \ + (sizeof(v) < sizeof(type)) ? \ + ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \ + (type) (v); \ +}) + /* * ctf_bitfield_write - write integer to a bitfield in native endianness * @@ -56,12 +76,12 @@ #define _ctf_bitfield_write_le(ptr, _start, _length, _v) \ do { \ + typeof(_v) v = (_v); \ typeof(*(ptr)) mask, cmask; \ + unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \ unsigned long start = (_start), length = (_length); \ - typeof(_v) v = (_v); \ unsigned long start_unit, end_unit, this_unit; \ unsigned long end, cshift; /* cshift is "complement shift" */ \ - unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \ \ if (!length) \ break; \ @@ -81,6 +101,7 @@ do { \ if (end % ts) \ mask |= (~(typeof(*(ptr))) 0) << (end % ts); \ cmask = (typeof(*(ptr))) v << (start % ts); \ + cmask &= ~mask; \ (ptr)[this_unit] &= mask; \ (ptr)[this_unit] |= cmask; \ break; \ @@ -89,6 +110,7 @@ do { \ cshift = start % ts; \ mask = ~((~(typeof(*(ptr))) 0) << cshift); \ cmask = (typeof(*(ptr))) v << cshift; \ + cmask &= ~mask; \ (ptr)[this_unit] &= mask; \ (ptr)[this_unit] |= cmask; \ v = _ctf_piecewise_rshift(v, ts - cshift); \ @@ -103,6 +125,7 @@ do { \ if (end % ts) { \ mask = (~(typeof(*(ptr))) 0) << (end % ts); \ cmask = (typeof(*(ptr))) v; \ + cmask &= ~mask; \ (ptr)[this_unit] &= mask; \ (ptr)[this_unit] |= cmask; \ } else \ @@ -112,11 +135,11 @@ do { \ #define _ctf_bitfield_write_be(ptr, _start, _length, _v) \ do { \ typeof(_v) v = (_v); \ + typeof(*(ptr)) mask, cmask; \ + unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \ unsigned long start = _start, length = _length; \ unsigned long start_unit, end_unit, this_unit; \ unsigned long end, cshift; /* cshift is "complement shift" */ \ - typeof(*(ptr)) mask, cmask; \ - unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \ \ if (!length) \ break; \ @@ -136,6 +159,7 @@ do { \ if (start % ts) \ mask |= (~((typeof(*(ptr))) 0)) << (ts - (start % ts)); \ cmask = (typeof(*(ptr))) v << ((ts - (end % ts)) % ts); \ + cmask &= ~mask; \ (ptr)[this_unit] &= mask; \ (ptr)[this_unit] |= cmask; \ break; \ @@ -144,13 +168,14 @@ do { \ cshift = end % ts; \ mask = ~((~(typeof(*(ptr))) 0) << (ts - cshift)); \ cmask = (typeof(*(ptr))) v << (ts - cshift); \ + cmask &= ~mask; \ (ptr)[this_unit] &= mask; \ (ptr)[this_unit] |= cmask; \ v = _ctf_piecewise_rshift(v, cshift); \ end -= cshift; \ this_unit--; \ } \ - for (; (long)this_unit >= (long)start_unit + 1; this_unit--) { \ + for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ (ptr)[this_unit] = (typeof(*(ptr))) v; \ v = _ctf_piecewise_rshift(v, ts); \ end -= ts; \ @@ -158,6 +183,7 @@ do { \ if (start % ts) { \ mask = (~(typeof(*(ptr))) 0) << (ts - (start % ts)); \ cmask = (typeof(*(ptr))) v; \ + cmask &= ~mask; \ (ptr)[this_unit] &= mask; \ (ptr)[this_unit] |= cmask; \ } else \ @@ -198,152 +224,167 @@ do { \ #endif -#if 0 -#define _ctf_bitfield_read_le(ptr, _start, _length, _vptr) \ +#define _ctf_bitfield_read_le(ptr, _start, _length, vptr) \ do { \ - typeof(_vptr) vptr = (_vptr); \ + typeof(*(vptr)) v; \ + typeof(*(ptr)) mask, cmask; \ + unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \ unsigned long start = _start, length = _length; \ unsigned long start_unit, end_unit, this_unit; \ unsigned long end, cshift; /* cshift is "complement shift" */ \ + \ + if (!length) { \ + *(vptr) = 0; \ + break; \ + } \ + \ + end = start + length; \ + start_unit = start / ts; \ + end_unit = (end + (ts - 1)) / ts; \ + \ + this_unit = end_unit - 1; \ + if (_ctf_is_signed_type(typeof(v)) \ + && ((ptr)[this_unit] & ((typeof(*(ptr))) 1 << ((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 = ~((~(typeof(*(ptr))) 0) << (end - start)); \ + cmask &= mask; \ + } \ + v = _ctf_piecewise_lshift(v, end - start); \ + v |= _ctf_unsigned_cast(typeof(v), cmask); \ + *(vptr) = v; \ + break; \ + } \ + if (end % ts) { \ + cshift = end % ts; \ + mask = ~((~(typeof(*(ptr))) 0) << cshift); \ + cmask = (ptr)[this_unit]; \ + cmask &= mask; \ + v = _ctf_piecewise_lshift(v, cshift); \ + v |= _ctf_unsigned_cast(typeof(v), cmask); \ + end -= cshift; \ + this_unit--; \ + } \ + for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \ + v = _ctf_piecewise_lshift(v, ts); \ + v |= _ctf_unsigned_cast(typeof(v), (ptr)[this_unit]); \ + end -= ts; \ + } \ + if (start % ts) { \ + mask = ~((~(typeof(*(ptr))) 0) << (ts - (start % ts))); \ + cmask = (ptr)[this_unit]; \ + cmask >>= (start % ts); \ + cmask &= mask; \ + v = _ctf_piecewise_lshift(v, ts - (start % ts)); \ + v |= _ctf_unsigned_cast(typeof(v), cmask); \ + } else { \ + v = _ctf_piecewise_lshift(v, ts); \ + v |= _ctf_unsigned_cast(typeof(v), (ptr)[this_unit]); \ + } \ + *(vptr) = v; \ +} while (0) + +#define _ctf_bitfield_read_be(ptr, _start, _length, vptr) \ +do { \ + typeof(*(vptr)) v; \ typeof(*(ptr)) mask, cmask; \ unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \ + unsigned long start = _start, length = _length; \ + unsigned long start_unit, end_unit, this_unit; \ + unsigned long end, cshift; /* cshift is "complement shift" */ \ \ - if (!length) \ + if (!length) { \ + *(vptr) = 0; \ break; \ + } \ \ end = start + length; \ start_unit = start / ts; \ end_unit = (end + (ts - 1)) / ts; \ + \ + this_unit = start_unit; \ + if (_ctf_is_signed_type(typeof(v)) \ + && ((ptr)[this_unit] & ((typeof(*(ptr))) 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 = ~((~(typeof(*(ptr))) 0) << (end - start)); \ + cmask &= mask; \ + } \ + v = _ctf_piecewise_lshift(v, end - start); \ + v |= _ctf_unsigned_cast(typeof(v), cmask); \ + *(vptr) = v; \ + break; \ + } \ + if (start % ts) { \ + mask = ~((~(typeof(*(ptr))) 0) << (ts - (start % ts))); \ + cmask = (ptr)[this_unit]; \ + cmask &= mask; \ + v = _ctf_piecewise_lshift(v, ts - (start % ts)); \ + v |= _ctf_unsigned_cast(typeof(v), cmask); \ + start += ts - (start % ts); \ + this_unit++; \ + } \ + for (; this_unit < end_unit - 1; this_unit++) { \ + v = _ctf_piecewise_lshift(v, ts); \ + v |= _ctf_unsigned_cast(typeof(v), (ptr)[this_unit]); \ + start += ts; \ + } \ + if (end % ts) { \ + mask = ~((~(typeof(*(ptr))) 0) << (end % ts)); \ + cmask = (ptr)[this_unit]; \ + cmask >>= ts - (end % ts); \ + cmask &= mask; \ + v = _ctf_piecewise_lshift(v, end % ts); \ + v |= _ctf_unsigned_cast(typeof(v), cmask); \ + } else { \ + v = _ctf_piecewise_lshift(v, ts); \ + v |= _ctf_unsigned_cast(typeof(v), (ptr)[this_unit]); \ + } \ + *(vptr) = v; \ } while (0) -#endif //0 - /* - * Read a bitfield byte-wise. This function is arch-agnostic. + * ctf_bitfield_read - read integer from a bitfield in native endianness + * ctf_bitfield_read_le - read integer from a bitfield in little endian + * ctf_bitfield_read_be - read integer from a bitfield in big endian */ -static inline -uint64_t _ctf_bitfield_read_64(const unsigned char *ptr, - unsigned long start, unsigned long len, - int byte_order, int signedness) -{ - long start_unit, end_unit, this_unit; - unsigned long end, cshift; /* cshift is "complement shift" */ - unsigned long ts = sizeof(unsigned char) * CHAR_BIT; - unsigned char mask, cmask; - uint64_t v = 0; - - if (!len) - return 0; - end = start + len; - start_unit = start / ts; - end_unit = (end + (ts - 1)) / ts; - - /* - * We can now fill v piece-wise, from lower bits to upper bits. - * We read the bitfield in the opposite direction it was written. - */ - switch (byte_order) { - case LITTLE_ENDIAN: - this_unit = end_unit - 1; - if (signedness) { - if (ptr[this_unit] & (1U << ((end % ts ? : ts) - 1))) - v = ~(uint64_t) 0; - } - if (start_unit == end_unit - 1) { - mask = (~(unsigned char) 0) << (end % ts ? : ts); - mask |= ~((~(unsigned char) 0) << (start % ts)); - cmask = ptr[this_unit]; - cmask &= ~mask; - cmask >>= (start % ts); - v <<= end - start; - v |= cmask; - break; - } - if (end % ts) { - cshift = (end % ts ? : ts); - mask = (~(unsigned char) 0) << cshift; - cmask = ptr[this_unit]; - cmask &= ~mask; - v <<= cshift; - v |= (uint64_t) cmask; - end -= cshift; - this_unit--; - } - for (; this_unit >= start_unit + 1; this_unit--) { - v <<= ts; - v |= (uint64_t) ptr[this_unit]; - end -= ts; - } - if (start % ts) { - cmask = ptr[this_unit] >> (start % ts); - v <<= ts - (start % ts); - v |= (uint64_t) cmask; - } else { - v <<= ts; - v |= (uint64_t) ptr[this_unit]; - } - break; - case BIG_ENDIAN: - this_unit = start_unit; - if (signedness) { - if (ptr[this_unit] & (1U << (ts - (start % ts) - 1))) - v = ~(uint64_t) 0; - } - if (start_unit == end_unit - 1) { - mask = (~(unsigned char) 0) << (ts - (start % ts)); - mask |= ~((~(unsigned char) 0) << ((ts - (end % ts)) % ts)); - cmask = ptr[this_unit]; - cmask &= ~mask; - cmask >>= (ts - (end % ts)) % ts; - v <<= end - start; - v |= (uint64_t) cmask; - break; - } - if (start % ts) { - mask = (~(unsigned char) 0) << (ts - (start % ts)); - cmask = ptr[this_unit]; - cmask &= ~mask; - v <<= ts - (start % ts); - v |= (uint64_t) cmask; - start += ts - (start % ts); - this_unit++; - } - for (; this_unit < end_unit - 1; this_unit++) { - v <<= ts; - v |= (uint64_t) ptr[this_unit]; - start += ts; - } - if (end % ts) { - cmask = ptr[this_unit]; - cmask >>= (ts - (end % ts)) % ts; - v <<= (end % ts); - v |= (uint64_t) cmask; - } else { - v <<= ts; - v |= (uint64_t) ptr[this_unit]; - } - break; - default: - assert(0); /* TODO: support PDP_ENDIAN */ - } - return v; -} - -static inline -uint64_t ctf_bitfield_unsigned_read(const uint8_t *ptr, - unsigned long start, unsigned long len, - int byte_order) -{ - return (uint64_t) _ctf_bitfield_read_64(ptr, start, len, byte_order, 0); -} - -static inline -int64_t ctf_bitfield_signed_read(const uint8_t *ptr, - unsigned long start, unsigned long len, - int byte_order) -{ - return (int64_t) _ctf_bitfield_read_64(ptr, start, len, byte_order, 1); -} +#if (BYTE_ORDER == LITTLE_ENDIAN) + +#define ctf_bitfield_read(ptr, _start, _length, _vptr) \ + _ctf_bitfield_read_le(ptr, _start, _length, _vptr) + +#define ctf_bitfield_read_le(ptr, _start, _length, _vptr) \ + _ctf_bitfield_read_le(ptr, _start, _length, _vptr) + +#define ctf_bitfield_read_be(ptr, _start, _length, _vptr) \ + _ctf_bitfield_read_be((const uint8_t *) (ptr), _start, _length, _vptr) + +#elif (BYTE_ORDER == BIG_ENDIAN) + +#define ctf_bitfield_read(ptr, _start, _length, _vptr) \ + _ctf_bitfield_read_be(ptr, _start, _length, _vptr) + +#define ctf_bitfield_read_le(ptr, _start, _length, _vptr) \ + _ctf_bitfield_read_le((const uint8_t *) (ptr), _start, _length, _vptr) + +#define ctf_bitfield_read_be(ptr, _start, _length, _vptr) \ + _ctf_bitfield_read_be(ptr, _start, _length, _vptr) + +#else /* (BYTE_ORDER == PDP_ENDIAN) */ + +#error "Byte order not supported" + +#endif #endif /* _CTF_BITFIELD_H */ diff --git a/include/ctf/ctf-types-bitfield.h b/include/ctf/ctf-types-bitfield.h index 4657a28f..a6764bf5 100644 --- a/include/ctf/ctf-types-bitfield.h +++ b/include/ctf/ctf-types-bitfield.h @@ -14,14 +14,33 @@ #include #include -/* - * ctf_bitfield_unsigned_read and ctf_bitfield_signed_read are defined by - * bitfield.h. - * - * The write primitives below are provided as wrappers over - * ctf_bitfield_write_le and ctf_bitfield_write_be to specify per-byte write of - * signed/unsigned integers through a standard API. - */ +static inline +uint64_t ctf_bitfield_unsigned_read(const uint8_t *ptr, + unsigned long start, unsigned long len, + int byte_order) +{ + uint64_t v; + + if (byte_order == LITTLE_ENDIAN) + ctf_bitfield_read_le(ptr, start, len, &v); + else + ctf_bitfield_read_be(ptr, start, len, &v); + return v; +} + +static inline +int64_t ctf_bitfield_signed_read(const uint8_t *ptr, + unsigned long start, unsigned long len, + int byte_order) +{ + int64_t v; + + if (byte_order == LITTLE_ENDIAN) + ctf_bitfield_read_le(ptr, start, len, &v); + else + ctf_bitfield_read_be(ptr, start, len, &v); + return v; +} static inline size_t ctf_bitfield_unsigned_write(uint8_t *ptr, diff --git a/tests/test-bitfield.c b/tests/test-bitfield.c index 2fc2e3a0..16b2d2e4 100644 --- a/tests/test-bitfield.c +++ b/tests/test-bitfield.c @@ -140,7 +140,7 @@ int run_test_unsigned(void) for (l = nrbits; l < (CHAR_BIT * TEST_LEN) - s; l++) { init_byte_array(target.c, TEST_LEN, 0xFF); ctf_bitfield_write(target.c, s, l, src); - readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 0); + ctf_bitfield_read(target.c, s, l, &readval); if (readval != src) { printf("Error (bytewise) src %lX read %llX shift %d len %d\n", src, readval, s, l); @@ -150,7 +150,7 @@ int run_test_unsigned(void) init_byte_array(target.c, TEST_LEN, 0xFF); ctf_bitfield_write(target.s, s, l, src); - readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 0); + ctf_bitfield_read(target.c, s, l, &readval); if (readval != src) { printf("Error (shortwise) src %lX read %llX shift %d len %d\n", src, readval, s, l); @@ -160,7 +160,7 @@ int run_test_unsigned(void) init_byte_array(target.c, TEST_LEN, 0xFF); ctf_bitfield_write(target.i, s, l, src); - readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 0); + ctf_bitfield_read(target.c, s, l, &readval); if (readval != src) { printf("Error (intwise) src %lX read %llX shift %d len %d\n", src, readval, s, l); @@ -170,7 +170,7 @@ int run_test_unsigned(void) init_byte_array(target.c, TEST_LEN, 0xFF); ctf_bitfield_write(target.l, s, l, src); - readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 0); + ctf_bitfield_read(target.c, s, l, &readval); if (readval != src) { printf("Error (longwise) src %lX read %llX shift %d len %d\n", src, readval, s, l); @@ -180,7 +180,7 @@ int run_test_unsigned(void) init_byte_array(target.c, TEST_LEN, 0xFF); ctf_bitfield_write(target.ll, s, l, src); - readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 0); + ctf_bitfield_read(target.c, s, l, &readval); if (readval != src) { printf("Error (longlongwise) src %lX read %llX shift %d len %d\n", src, readval, s, l); @@ -222,7 +222,7 @@ int run_test_signed(void) for (l = nrbits; l < (8 * TEST_LEN) - s; l++) { init_byte_array(target.c, TEST_LEN, 0x0); ctf_bitfield_write(target.c, s, l, src); - readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 1); + ctf_bitfield_read(target.c, s, l, &readval); if (readval != src) { printf("Error (bytewise) src %lX read %llX shift %d len %d\n", src, readval, s, l); @@ -232,7 +232,7 @@ int run_test_signed(void) init_byte_array(target.c, TEST_LEN, 0x0); ctf_bitfield_write(target.s, s, l, src); - readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 1); + ctf_bitfield_read(target.c, s, l, &readval); if (readval != src) { printf("Error (shortwise) src %lX read %llX shift %d len %d\n", src, readval, s, l); @@ -242,7 +242,7 @@ int run_test_signed(void) init_byte_array(target.c, TEST_LEN, 0x0); ctf_bitfield_write(target.i, s, l, src); - readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 1); + ctf_bitfield_read(target.c, s, l, &readval); if (readval != src) { printf("Error (intwise) src %lX read %llX shift %d len %d\n", src, readval, s, l); @@ -252,7 +252,7 @@ int run_test_signed(void) init_byte_array(target.c, TEST_LEN, 0x0); ctf_bitfield_write(target.l, s, l, src); - readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 1); + ctf_bitfield_read(target.c, s, l, &readval); if (readval != src) { printf("Error (longwise) src %lX read %llX shift %d len %d\n", src, readval, s, l); @@ -262,7 +262,7 @@ int run_test_signed(void) init_byte_array(target.c, TEST_LEN, 0x0); ctf_bitfield_write(target.ll, s, l, src); - readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 1); + ctf_bitfield_read(target.c, s, l, &readval); if (readval != src) { printf("Error (longlongwise) src %lX read %llX shift %d len %d\n", src, readval, s, l); @@ -363,7 +363,7 @@ int main(int argc, char **argv) printf("lluwise\n"); print_byte_array(target.c, 8); - readval = _ctf_bitfield_read_64(target.c, shift, len, BYTE_ORDER, 0); + ctf_bitfield_read(target.c, shift, len, &readval); printf("read: %llX\n", readval); ret = run_test();