diff options
-rw-r--r-- | lib/util/intcode.h | 203 | ||||
-rw-r--r-- | pm_config.in.h | 54 |
2 files changed, 224 insertions, 33 deletions
diff --git a/lib/util/intcode.h b/lib/util/intcode.h index 155e47e1..dd42f669 100644 --- a/lib/util/intcode.h +++ b/lib/util/intcode.h @@ -1,10 +1,78 @@ #ifndef INTCODE_H_INCLUDED #define INTCODE_H_INCLUDED -#include "pm_config.h" /* For uint32_t, BYTE_ORDER */ +#include "pm_config.h" /* For uint32_t, BYTE_ORDER, HAVE_INT64 */ static unsigned int const pm_byteOrder = BYTE_ORDER; +typedef struct { +/*---------------------------------------------------------------------------- + This is a big-endian representation of a 16 bit integer. I.e. + bytes[0] is the most significant 8 bits; bytes[1] is the least + significant 8 bits of the number in pure binary. + + On a big-endian machines, this is bit for bit identical to uint16_t. + On a little-endian machine, it isn't. + + This is an important data type because decent file formats use + big-endian -- they don't care if some CPU happens to use some other + code for its own work. +-----------------------------------------------------------------------------*/ + unsigned char bytes[2]; +} bigend16; + + +static __inline__ uint16_t +pm_uintFromBigend16(bigend16 const arg) { + + uint16_t retval; + + switch (pm_byteOrder) { + case BIG_ENDIAN: { + union { + bigend16 bigend; + uint16_t native; + } converter; + converter.bigend = arg; + retval = converter.native; + } break; + + default: { + retval = + (arg.bytes[0] << 8) | + (arg.bytes[1] << 0); + } + } + return retval; +} + + + +static __inline__ bigend16 +pm_bigendFromUint16(uint16_t const arg) { + + bigend16 retval; + + switch (pm_byteOrder) { + case BIG_ENDIAN: { + union { + bigend16 bigend; + uint16_t native; + } converter; + converter.native = arg; + retval = converter.bigend; + } break; + + default: { + uint16_t shift; + shift = arg; + retval.bytes[1] = shift; /* Takes lower 8 bits */ + shift >>= 8; + retval.bytes[0] = shift; /* Takes lower 8 bits */ + } + } + return retval; +} typedef struct { /*---------------------------------------------------------------------------- @@ -34,19 +102,30 @@ pm_uintFromBigend32(bigend32 const arg) { bigend32 bigend; uint32_t native; } converter; - converter.bigend = arg; - retval = converter.native; - }; break; + } break; + +#if HAVE_GCC_BSWAP case LITTLE_ENDIAN: { + /* Use GCC built-in */ + union { + bigend32 bigend; + uint32_t native; + } converter; + converter.bigend = arg; + retval = __builtin_bswap32(converter.native); + } break; +#endif + + default: retval = (arg.bytes[0] << 24) | (arg.bytes[1] << 16) | (arg.bytes[2] << 8) | (arg.bytes[3] << 0); - } break; } + return retval; } @@ -63,12 +142,23 @@ pm_bigendFromUint32(uint32_t const arg) { bigend32 bigend; uint32_t native; } converter; - converter.native = arg; - retval = converter.bigend; } break; + +#if HAVE_GCC_BSWAP case LITTLE_ENDIAN: { + /* Use GCC built-in */ + union { + bigend32 bigend; + uint32_t native; + } converter; + converter.native = __builtin_bswap32(arg); + retval = converter.bigend; + } break; +#endif + + default: { uint32_t shift; shift = arg; retval.bytes[3] = shift; /* Takes lower 8 bits */ @@ -78,80 +168,127 @@ pm_bigendFromUint32(uint32_t const arg) { retval.bytes[1] = shift; /* Takes lower 8 bits */ shift >>= 8; retval.bytes[0] = shift; /* Takes lower 8 bits */ - } break; + } } return retval; } + +#if HAVE_INT64 + typedef struct { /*---------------------------------------------------------------------------- - This is a big-endian representation of a 16 bit integer. I.e. - bytes[0] is the most significant 8 bits; bytes[1] is the least + This is a big-endian representation of a 64 bit integer. I.e. + bytes[0] is the most significant 8 bits; bytes[7] is the least significant 8 bits of the number in pure binary. - On a big-endian machines, this is bit for bit identical to uint16_t. + On a big-endian machines, this is bit for bit identical to uint64_t. On a little-endian machine, it isn't. This is an important data type because decent file formats use big-endian -- they don't care if some CPU happens to use some other code for its own work. + + uint64_t is supported only when available. -----------------------------------------------------------------------------*/ - unsigned char bytes[2]; -} bigend16; + unsigned char bytes[8]; +} bigend64; -static __inline__ uint16_t -pm_uintFromBigend16(bigend16 const arg) { +static __inline__ uint64_t +pm_uintFromBigend64(bigend64 const arg) { - uint16_t retval; + uint64_t retval; switch (pm_byteOrder) { case BIG_ENDIAN: { union { - bigend16 bigend; - uint16_t native; + bigend64 bigend; + uint64_t native; } converter; - converter.bigend = arg; - retval = converter.native; - }; break; + } break; + +#if HAVE_GCC_BSWAP case LITTLE_ENDIAN: { - retval = - (arg.bytes[0] << 16) | - (arg.bytes[1] << 8); + /* Use GCC built-in */ + union { + bigend64 bigend; + uint64_t native; + } converter; + converter.bigend = arg; + retval = __builtin_bswap64(converter.native); } break; +#endif + default: + retval = + ((uint64_t)arg.bytes[0] << 56) | ((uint64_t)arg.bytes[1] << 48) | + ((uint64_t)arg.bytes[2] << 40) | ((uint64_t)arg.bytes[3] << 32) | + ((uint64_t)arg.bytes[4] << 24) | ((uint64_t)arg.bytes[5] << 16) | + ((uint64_t)arg.bytes[6] << 8) | ((uint64_t)arg.bytes[7] << 0); } return retval; } -static __inline__ bigend16 -pm_bigendFromUint16(uint16_t const arg) { +static __inline__ bigend64 +pm_bigendFromUint64(uint64_t const arg) { - bigend16 retval; + bigend64 retval; switch (pm_byteOrder) { case BIG_ENDIAN: { union { - bigend16 bigend; - uint16_t native; + bigend64 bigend; + uint64_t native; } converter; - converter.native = arg; - retval = converter.bigend; } break; + +#if HAVE_GCC_BSWAP case LITTLE_ENDIAN: { - uint16_t shift; + + /* Use GCC built-in */ + union { + bigend64 bigend; + uint64_t native; + } converter; + converter.native = __builtin_bswap64(arg); + retval = converter.bigend; + } break; +#endif + + default: { + uint64_t shift; shift = arg; + retval.bytes[7] = shift; /* Takes lower 8 bits */ + shift >>= 8; + retval.bytes[6] = shift; /* Takes lower 8 bits */ + shift >>= 8; + retval.bytes[5] = shift; /* Takes lower 8 bits */ + shift >>= 8; + retval.bytes[4] = shift; /* Takes lower 8 bits */ + shift >>= 8; + retval.bytes[3] = shift; /* Takes lower 8 bits */ + shift >>= 8; + retval.bytes[2] = shift; /* Takes lower 8 bits */ + shift >>= 8; retval.bytes[1] = shift; /* Takes lower 8 bits */ shift >>= 8; retval.bytes[0] = shift; /* Takes lower 8 bits */ - } break; + } } return retval; } +#endif /* HAVE_INT64 */ + #endif + + + + + diff --git a/pm_config.in.h b/pm_config.in.h index c822355e..c44bc72c 100644 --- a/pm_config.in.h +++ b/pm_config.in.h @@ -198,6 +198,60 @@ extern int rand(); #endif #endif +/* CONFIGURE: GNUC extensions are used in performance critical places + when available. Test whether they exist. + + Turn off by defining NO_GCC_BUILTINS. + + Note that though these influence the code produced, the compiler + setting ultimately decides what operands are used. If you + want a generic build, check the manual and adjust CFLAGS in + config.mk accordingly. + + For example, if you want binaries that run on all Intel x86-32 + family CPUs back to 80386, adding "-march=i386" to CFLAGS in + config.mk is much better than setting NO_GCC_BUILTINS to 1. + If you want to be extra sure use: + "-march=i386 -mno-mmx -mno-sse -DNO_GCC_BUILTINS" +*/ + +#if defined(__GNUC__) && !defined(NO_GCC_BUILTINS) + #define GCCVERSION __GNUC__*100 + __GNUC_MINOR__ +#else + #define GCCVERSION 0 +#endif + +#ifndef HAVE_GCC_MMXSSE +#if GCCVERSION >=301 && defined(__MMX__) && defined(__SSE__) + #define HAVE_GCC_MMXSSE 1 + /* Use GCC builtins to directly access MMX/SSE features */ +#else + #define HAVE_GCC_MMXSSE 0 +#endif +#endif + +#ifndef HAVE_GCC_BITCOUNT +#if GCCVERSION >=304 + #define HAVE_GCC_BITCOUNT 1 + /* Use __builtin_clz(), __builtin_ctz() (and variants for long) + to count leading/trailing 0s in int (and long). */ +#else + #define HAVE_GCC_BITCOUNT 0 +#endif +#endif + +#ifndef HAVE_GCC_BSWAP +#if GCCVERSION >=403 + #define HAVE_GCC_BSWAP 1 + /* Use __builtin_bswap32(), __builtin_bswap64() for endian conversion. + Available from GCC v 4.3 onward. + NOTE: On intel CPUs this may produce the bswap operand which is not + available on 80386. */ +#else + #define HAVE_GCC_BSWAP 0 +#endif +#endif + /* CONFIGURE: Some systems seem to need more than standard program linkage |