about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-05-01 02:10:15 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-05-01 02:10:15 +0000
commit76bbc70fe011921c87f3a21a9175152bae293cdf (patch)
tree81f642174b1507dea2a4855dc13a1a096cb3c31b
parentb5049ee52a113d7bfa24a7bb2fdd9c0e6292dc2f (diff)
downloadnetpbm-mirror-76bbc70fe011921c87f3a21a9175152bae293cdf.tar.gz
netpbm-mirror-76bbc70fe011921c87f3a21a9175152bae293cdf.tar.xz
netpbm-mirror-76bbc70fe011921c87f3a21a9175152bae293cdf.zip
integer code handling improvements
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@903 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r--lib/util/intcode.h203
-rw-r--r--pm_config.in.h54
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