Optimised code for encoding/decoding integers when the underlying architecture has the right endianness and allows unaligned accesses.
This commit is contained in:
parent
5db2d48b12
commit
90bc9406c3
2 changed files with 115 additions and 5 deletions
104
src/inner.h
104
src/inner.h
|
|
@ -118,7 +118,6 @@
|
|||
* Determine whether x86 AES instructions are understood by the compiler.
|
||||
*/
|
||||
#ifndef BR_AES_X86NI
|
||||
|
||||
#if (__i386__ || __x86_64__) \
|
||||
&& ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) \
|
||||
|| (__clang_major__ > 3 \
|
||||
|
|
@ -220,58 +219,124 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Detect support for unaligned accesses with known endianness.
|
||||
*
|
||||
* x86 (both 32-bit and 64-bit) is little-endian and allows unaligned
|
||||
* accesses.
|
||||
*
|
||||
* POWER/PowerPC allows unaligned accesses when big-endian. POWER8 and
|
||||
* later also allow unaligned accesses when little-endian.
|
||||
*/
|
||||
#if !defined BR_LE_UNALIGNED && !defined BR_BE_UNALIGNED
|
||||
|
||||
#if __i386 || __i386__ || __x86_64__ || _M_IX86 || _M_X64
|
||||
#define BR_LE_UNALIGNED 1
|
||||
#elif BR_POWER8_BE
|
||||
#define BR_BE_UNALIGNED 1
|
||||
#elif BR_POWER8_LE
|
||||
#define BR_LE_UNALIGNED 1
|
||||
#elif (__powerpc__ || __powerpc64__ || _M_PPC || _ARCH_PPC || _ARCH_PPC64) \\
|
||||
&& __BIG_ENDIAN__
|
||||
#define BR_BE_UNALIGNED 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* ==================================================================== */
|
||||
/*
|
||||
* Encoding/decoding functions.
|
||||
*
|
||||
* 32-bit and 64-bit decoding, both little-endian and big-endian, is
|
||||
* implemented with the inline functions below. These functions are
|
||||
* generic: they don't depend on the architecture natural endianness,
|
||||
* and they can handle unaligned accesses. Optimized versions for some
|
||||
* specific architectures may be implemented at a later time.
|
||||
* implemented with the inline functions below.
|
||||
*
|
||||
* When allowed by some compile-time options (autodetected or provided),
|
||||
* optimised code is used, to perform direct memory access when the
|
||||
* underlying architecture supports it, both for endianness and
|
||||
* alignment. This, however, may trigger strict aliasing issues; the
|
||||
* code below uses unions to perform (supposedly) safe type punning.
|
||||
* Since the C aliasing rules are relatively complex and were amended,
|
||||
* or at least re-explained with different phrasing, in all successive
|
||||
* versions of the C standard, it is always a bit risky to bet that any
|
||||
* specific version of a C compiler got it right, for some notion of
|
||||
* "right".
|
||||
*/
|
||||
|
||||
typedef union {
|
||||
uint16_t u;
|
||||
unsigned char b[sizeof(uint16_t)];
|
||||
} br_union_u16;
|
||||
|
||||
typedef union {
|
||||
uint32_t u;
|
||||
unsigned char b[sizeof(uint32_t)];
|
||||
} br_union_u32;
|
||||
|
||||
typedef union {
|
||||
uint64_t u;
|
||||
unsigned char b[sizeof(uint64_t)];
|
||||
} br_union_u64;
|
||||
|
||||
static inline void
|
||||
br_enc16le(void *dst, unsigned x)
|
||||
{
|
||||
#if BR_LE_UNALIGNED
|
||||
((br_union_u16 *)dst)->u = x;
|
||||
#else
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
buf[0] = (unsigned char)x;
|
||||
buf[1] = (unsigned char)(x >> 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
br_enc16be(void *dst, unsigned x)
|
||||
{
|
||||
#if BR_BE_UNALIGNED
|
||||
((br_union_u16 *)dst)->u = x;
|
||||
#else
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
buf[0] = (unsigned char)(x >> 8);
|
||||
buf[1] = (unsigned char)x;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
br_dec16le(const void *src)
|
||||
{
|
||||
#if BR_LE_UNALIGNED
|
||||
return ((const br_union_u16 *)src)->u;
|
||||
#else
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
return (unsigned)buf[0] | ((unsigned)buf[1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
br_dec16be(const void *src)
|
||||
{
|
||||
#if BR_BE_UNALIGNED
|
||||
return ((const br_union_u16 *)src)->u;
|
||||
#else
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
return ((unsigned)buf[0] << 8) | (unsigned)buf[1];
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
br_enc32le(void *dst, uint32_t x)
|
||||
{
|
||||
#if BR_LE_UNALIGNED
|
||||
((br_union_u32 *)dst)->u = x;
|
||||
#else
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
|
|
@ -279,11 +344,15 @@ br_enc32le(void *dst, uint32_t x)
|
|||
buf[1] = (unsigned char)(x >> 8);
|
||||
buf[2] = (unsigned char)(x >> 16);
|
||||
buf[3] = (unsigned char)(x >> 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
br_enc32be(void *dst, uint32_t x)
|
||||
{
|
||||
#if BR_BE_UNALIGNED
|
||||
((br_union_u32 *)dst)->u = x;
|
||||
#else
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
|
|
@ -291,11 +360,15 @@ br_enc32be(void *dst, uint32_t x)
|
|||
buf[1] = (unsigned char)(x >> 16);
|
||||
buf[2] = (unsigned char)(x >> 8);
|
||||
buf[3] = (unsigned char)x;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
br_dec32le(const void *src)
|
||||
{
|
||||
#if BR_LE_UNALIGNED
|
||||
return ((const br_union_u32 *)src)->u;
|
||||
#else
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
|
|
@ -303,11 +376,15 @@ br_dec32le(const void *src)
|
|||
| ((uint32_t)buf[1] << 8)
|
||||
| ((uint32_t)buf[2] << 16)
|
||||
| ((uint32_t)buf[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
br_dec32be(const void *src)
|
||||
{
|
||||
#if BR_BE_UNALIGNED
|
||||
return ((const br_union_u32 *)src)->u;
|
||||
#else
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
|
|
@ -315,46 +392,63 @@ br_dec32be(const void *src)
|
|||
| ((uint32_t)buf[1] << 16)
|
||||
| ((uint32_t)buf[2] << 8)
|
||||
| (uint32_t)buf[3];
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
br_enc64le(void *dst, uint64_t x)
|
||||
{
|
||||
#if BR_LE_UNALIGNED
|
||||
((br_union_u64 *)dst)->u = x;
|
||||
#else
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
br_enc32le(buf, (uint32_t)x);
|
||||
br_enc32le(buf + 4, (uint32_t)(x >> 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
br_enc64be(void *dst, uint64_t x)
|
||||
{
|
||||
#if BR_BE_UNALIGNED
|
||||
((br_union_u64 *)dst)->u = x;
|
||||
#else
|
||||
unsigned char *buf;
|
||||
|
||||
buf = dst;
|
||||
br_enc32be(buf, (uint32_t)(x >> 32));
|
||||
br_enc32be(buf + 4, (uint32_t)x);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
br_dec64le(const void *src)
|
||||
{
|
||||
#if BR_LE_UNALIGNED
|
||||
return ((const br_union_u64 *)src)->u;
|
||||
#else
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
return (uint64_t)br_dec32le(buf)
|
||||
| ((uint64_t)br_dec32le(buf + 4) << 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
br_dec64be(const void *src)
|
||||
{
|
||||
#if BR_BE_UNALIGNED
|
||||
return ((const br_union_u64 *)src)->u;
|
||||
#else
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = src;
|
||||
return ((uint64_t)br_dec32be(buf) << 32)
|
||||
| (uint64_t)br_dec32be(buf + 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue