diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2009-05-01 02:25:58 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2009-05-01 02:25:58 +0000 |
commit | 39dd39596b97f09b2e84ed612e60a0402dc3ab41 (patch) | |
tree | e244aed80596da9fac78d06db2ed57a5f351fa16 | |
parent | 76bbc70fe011921c87f3a21a9175152bae293cdf (diff) | |
download | netpbm-mirror-39dd39596b97f09b2e84ed612e60a0402dc3ab41.tar.gz netpbm-mirror-39dd39596b97f09b2e84ed612e60a0402dc3ab41.tar.xz netpbm-mirror-39dd39596b97f09b2e84ed612e60a0402dc3ab41.zip |
improvements to efficient word access
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@904 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r-- | buildtools/endiangen.c | 6 | ||||
-rw-r--r-- | common.mk | 4 | ||||
-rw-r--r-- | converter/pbm/pbmtog3.c | 1 | ||||
-rw-r--r-- | lib/util/wordaccess.h | 30 | ||||
-rw-r--r-- | lib/util/wordaccess_64_le.h | 48 | ||||
-rw-r--r-- | lib/util/wordaccess_gcc3_be.h | 17 | ||||
-rw-r--r-- | lib/util/wordaccess_gcc3_le.h | 56 | ||||
-rw-r--r-- | lib/util/wordaccess_generic.h | 74 | ||||
-rw-r--r-- | lib/util/wordintclz.h | 93 |
9 files changed, 136 insertions, 193 deletions
diff --git a/buildtools/endiangen.c b/buildtools/endiangen.c index 07560c10..6b88b896 100644 --- a/buildtools/endiangen.c +++ b/buildtools/endiangen.c @@ -59,9 +59,9 @@ byteOrder(void) { static unsigned int -bitsPerWord(void) { +bitsPerLong(void) { - return MAX(sizeof(long), sizeof(int)) * 8; + return sizeof(long) * 8; } @@ -87,7 +87,7 @@ main(int argc, char **argv) { byteOrder() == ENDIAN_LITTLE ? "LITTLE_ENDIAN" : "BIG_ENDIAN"); printf("#endif\n"); printf("\n"); - printf("#define BITS_PER_WORD %u\n", bitsPerWord()); + printf("#define BITS_PER_LONG %u\n", bitsPerLong()); return 0; } diff --git a/common.mk b/common.mk index 277c71a9..9e13a7c8 100644 --- a/common.mk +++ b/common.mk @@ -125,8 +125,8 @@ IMPORTINC_LIB_HEADERS := \ IMPORTINC_LIB_UTIL_HEADERS := \ bitarith.h bitreverse.h filename.h intcode.h floatcode.h mallocvar.h\ nsleep.h nstring.h pm_c_util.h shhopt.h \ - wordaccess.h wordaccess_64_le.h wordaccess_gcc3_be.h wordaccess_gcc3_le.h \ - wordaccess_generic.h \ + wordaccess.h wordaccess_64_le.h wordaccess_gcc3_be.h wordaccess_generic.h \ + wordintclz.h IMPORTINC_HEADERS := \ $(IMPORTINC_ROOT_HEADERS) \ diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c index 44d9a26b..f53bfaa0 100644 --- a/converter/pbm/pbmtog3.c +++ b/converter/pbm/pbmtog3.c @@ -23,6 +23,7 @@ #include "mallocvar.h" #include "bitreverse.h" #include "wordaccess.h" +#include "wordintclz.h" #include "g3.h" #include "pbm.h" diff --git a/lib/util/wordaccess.h b/lib/util/wordaccess.h index 08034361..2eaa2b24 100644 --- a/lib/util/wordaccess.h +++ b/lib/util/wordaccess.h @@ -36,31 +36,39 @@ work with that. We also assume that a char is 8 bits. + + HAVE_GCC_BITCOUNT and HAVE_GCC_BSWAP are set in pm_config.h + + BITS_PER_LONG is the number of bits in long int. */ #include "pm_config.h" -#if (!defined(WORDACCESS_GENERIC) \ - && defined(__GNUC__) && defined(__GLIBC__) \ - && (__GNUC__ * 100 + __GNUC_MINOR__ >= 304) ) - - #if BYTE_ORDER==BIG_ENDIAN /* defined by GCC */ +#if (!defined(WORDACCESS_GENERIC) && HAVE_GCC_BITCOUNT ) + #if BYTE_ORDER == BIG_ENDIAN /* See pm_config.h */ + /* Sun Sparc 64, etc */ #include "wordaccess_gcc3_be.h" - #elif defined(__ia64__) || defined(__amd64__) || defined(__x86_64__) - /* all these macros are defined by GCC */ - + #elif (BITS_PER_LONG == 64) + /* AMD Athlon 64, Intel x86_64, Intel Itanium, etc. */ #include "wordaccess_64_le.h" - #else + #elif (BITS_PER_LONG == 32) + /* Intel x86_32 (80386, 80486, Pentium), etc. */ + #include "wordaccess_generic.h" - #include "wordaccess_gcc3_le.h" + #else + /* Extremely rare case. + If long is neither 32 nor 64 bits, (say, 128) it comes here. + */ + #define WORDACCESS_GENERIC + #include "wordaccess_generic.h" #endif #else - + /* Non GCC, GCC prior to v.3.4 or WORDACCESS_GENERIC defined */ #include "wordaccess_generic.h" #endif diff --git a/lib/util/wordaccess_64_le.h b/lib/util/wordaccess_64_le.h index ad316df2..4d148ad2 100644 --- a/lib/util/wordaccess_64_le.h +++ b/lib/util/wordaccess_64_le.h @@ -2,28 +2,21 @@ This file is the part of wordaccess.h for use under these conditions: - * GCC (>=3.4), GLIBC - * 64 bit Little-Endian machines (IA64, X86-64, AMD64) -=============================================================================*/ - -/* - 64 bit hton and ntoh do not exist. Here we use bswap_64. - - While bswap_64 works on 64 bit data, __builtin_clzl works on "long" which - may or may not be 64 bits. Code provided to find the right data type and - file off any extra when necessary. -*/ - -#include <byteswap.h> /* See note above on bswap_64 */ - -#include "pm.h" + * GCC (>=3.4) (__builtin_clz appears in GCC 3.4) + * Little-Endian machines (IA64, X86-64, AMD64) + * 64 bit long +=============================================================================*/ + +#include "intcode.h" + typedef uint64_t wordint; typedef unsigned char wordintBytes[sizeof(wordint)]; + static __inline__ wordint -bytesToWordint(wordintBytes bytes) { - return ((wordint) bswap_64(*(wordint *)bytes)); +bytesToWordint(wordintBytes const bytes) { + return (wordint) pm_uintFromBigend64(*(bigend64*)bytes); } @@ -31,24 +24,5 @@ bytesToWordint(wordintBytes bytes) { static __inline__ void wordintToBytes(wordintBytes * const bytesP, wordint const wordInt) { - *(wordint *)bytesP = bswap_64(wordInt); -} - - - -static __inline__ unsigned int -wordintClz(wordint const x){ - - unsigned int s; - - if (x == 0) - return sizeof(wordint) * 8; - - /* Find the data type closest to 64 bits, and file off any extra. */ - else if ((s=sizeof(long int)) >= 8) - return (__builtin_clzl((long int)x << (s - 8) * 8)); - else if ((s=sizeof(long long int)) >= 8) - return (__builtin_clzll((long long int)x << (s - 8) * 8)); - else - pm_error("Long long int is less than 64 bits on this machine"); + *(bigend64*)bytesP = pm_bigendFromUint64(wordInt); } diff --git a/lib/util/wordaccess_gcc3_be.h b/lib/util/wordaccess_gcc3_be.h index 6f5d86fc..5aa63521 100644 --- a/lib/util/wordaccess_gcc3_be.h +++ b/lib/util/wordaccess_gcc3_be.h @@ -4,16 +4,6 @@ * GCC (>=3.4), GLIBC * Big-Endian machines - - __builtin_clz is available on GCC 3.4 and above - - Note that the clz scheme does not work and requires adjustment - if long type does not make use of all bits for data storage. - - This is unlikely. According to GNU MP (http://www.swox.com/gmp/), - in rare cases such as Cray, there are smaller data types that take up - the same space as long, but leave the higher bits silent. Currently, - there are no known such cases for data type long. *===========================================================================*/ typedef unsigned long int wordint; @@ -31,10 +21,3 @@ wordintToBytes(wordintBytes * const bytesP, wordint const wordInt) { *(wordint *)bytesP = wordInt; } - - - -static __inline__ unsigned int -wordintClz(wordint const x) { - return (x==0 ? sizeof(wordint)*8 : __builtin_clzl(x)); -} diff --git a/lib/util/wordaccess_gcc3_le.h b/lib/util/wordaccess_gcc3_le.h deleted file mode 100644 index 798566af..00000000 --- a/lib/util/wordaccess_gcc3_le.h +++ /dev/null @@ -1,56 +0,0 @@ -/*============================================================================= - - This file is the part of wordaccess.h for use under these - conditions: - - * GCC (>=3.4), GLIBC - * 32 bit Little-Endian machines (intel MPUs 80386, Pentium, etc.) - * Other non-Big-Endian machines (very rare) - -=============================================================================*/ - -typedef uint32_t wordint; -typedef unsigned char wordintBytes[sizeof(wordint)]; - -#include <sys/types.h> -#include <netinet/in.h> - -#include "pm.h" - -/* - Here we use the more widely used functions htonl and ntohl instead of - bswap_32. This makes possible the handling of weird byte ordering - (neither Big-Endian nor Little-Endian) schemes, if any. -*/ - -static __inline__ wordint -bytesToWordint(wordintBytes const bytes) { - return (wordint) ntohl(*(wordint *)bytes); -} - - - -static __inline__ void -wordintToBytes(wordintBytes * const bytesP, - wordint const wordInt) { - - *(wordint *)bytesP = htonl(wordInt); -} - - - -static __inline__ unsigned int -wordintClz(wordint const x) { - - /* Find the data type closest to 32 bits, and file off any extra. */ - - if (x == 0) - return sizeof(wordint) * 8; - else if (sizeof(int) >= 4) - return __builtin_clz((int)x << (sizeof(int) - 4) * 8); - else if (sizeof(long int) >= 4) - return __builtin_clzl((long int)x << (sizeof(long int) - 4) * 8); - else - pm_error("Long int is less than 32 bits on this machine"); -} - diff --git a/lib/util/wordaccess_generic.h b/lib/util/wordaccess_generic.h index 7f27ef74..94cc8124 100644 --- a/lib/util/wordaccess_generic.h +++ b/lib/util/wordaccess_generic.h @@ -5,85 +5,25 @@ * Compilers other than GCC * GCC before version 3.4 - * c libraries other than Glibc * Specified by the user with WORDACCESS_GENERIC =============================================================================*/ +#include "intcode.h" + typedef uint32_t wordint; typedef unsigned char wordintBytes[sizeof(wordint)]; + static __inline__ wordint -bytesToWordint(wordintBytes const bytes) { - wordint retval; - unsigned int i; +bytesToWordint(wordintBytes const bytes) { - /* Note that 'bytes' is a pointer, due to C array degeneration. - That means sizeof(bytes) isn't what you think it is. - */ - - for (i = 1, retval = bytes[0]; i < sizeof(wordint); ++i) { - retval = (retval << 8) + bytes[i]; - } - return retval; + return (wordint) pm_uintFromBigend32( * (bigend32*) bytes); } - static __inline__ void wordintToBytes(wordintBytes * const bytesP, - wordint const wordInt) { - - wordint buffer; - int i; - - for (i = sizeof(*bytesP)-1, buffer = wordInt; i >= 0; --i) { - (*bytesP)[i] = buffer & 0xFF; - buffer >>= 8; - } -} - -static unsigned char const clz8[256]= { - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - - - -static __inline__ unsigned int -clz16(wordint const x) { - if (x >> 8 != 0) - return clz8[x >> 8]; - else - return clz8[x] + 8; -} - - - -static __inline__ unsigned int -clz32(wordint const x) { - if (x >> 16 != 0) - return clz16(x >> 16); - else - return clz16(x) +16; -} - - + wordint const wordInt) { -static __inline__ unsigned int -wordintClz(wordint const x) { - return clz32(x); + * (bigend32*) bytesP = pm_bigendFromUint32((uint32_t)wordInt); } diff --git a/lib/util/wordintclz.h b/lib/util/wordintclz.h new file mode 100644 index 00000000..32e6ade8 --- /dev/null +++ b/lib/util/wordintclz.h @@ -0,0 +1,93 @@ +#ifndef WORDINTCLZ_H_INCLUDED +#define WORDINTCLZ_H_INCLUDED + +#if (!defined(WORDACCESS_GENERIC) && HAVE_GCC_BITCOUNT ) +/* + Compiler is GCC and has __builtin_clz() + wordint is long + + __builtin_clz is available on GCC 3.4 and above + + Note that the clz scheme does not work and requires adjustment + if long type does not make use of all bits for data storage. + + This is unlikely. According to GNU MP (http://www.swox.com/gmp/), + in rare cases such as Cray, there are smaller data types that take up + the same space as long, but leave the higher bits silent. + Currently, there are no known such cases for data type long. + */ + +static __inline__ unsigned int +wordintClz(wordint const x){ + + assert(sizeof(unsigned long int) == sizeof(wordint)); + + if (x == 0) + return sizeof(wordint) * 8; + else + return (__builtin_clzl( (unsigned long int) x )); +} + +#else + +/* wordint is uint32_t: exactly 32 bits wide */ + +static unsigned char const clz8[256]= { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + + +static __inline__ unsigned int +clz16(wordint const x) { + + if (x >> 8 != 0) + return clz8[x >> 8]; + else + return clz8[x] + 8; +} + + + +static __inline__ unsigned int +clz32(wordint const x) { + + if (x >> 16 != 0) + return clz16(x >> 16); + else + return clz16(x) + 16; +} + + + +static __inline__ unsigned int +wordintClz(wordint const x) { + + assert(sizeof(wordint) == 4); + + return clz32(x); +} + +/* Another way to calculate leading zeros: + x == 0 ? 32 : 31 - floor(log(x)/log(2)) + (Beware: insufficient precision will cause errors) +*/ + +#endif + +#endif |