changeset 15947:d1ff4390df13

ffsl: Optimize on 32-bit platforms. * lib/ffsl.h (FUNC): If TYPE has the same representation as 'int', just use ffs() without a loop.
author Bruno Haible <bruno@clisp.org>
date Fri, 14 Oct 2011 02:11:34 +0200
parents d0eb709725f5
children 0098fa655711
files ChangeLog lib/ffsl.h
diffstat 2 files changed, 31 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2011-10-13  Bruno Haible  <bruno@clisp.org>
 
+	ffsl: Optimize on 32-bit platforms.
+	* lib/ffsl.h (FUNC): If TYPE has the same representation as 'int', just
+	use ffs() without a loop.
+
 	ffsl, ffsll: Optimize for GCC.
 	* lib/ffsl.h (FUNC): Use GCC_BUILTIN if defined.
 	* lib/ffsl.c (GCC_BUILTIN): New macro.
--- a/lib/ffsl.h
+++ b/lib/ffsl.h
@@ -34,18 +34,34 @@
 #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined GCC_BUILTIN
   return GCC_BUILTIN (i);
 #else
-  int result = 0;
-  unsigned TYPE j = i;
+  if (sizeof (TYPE) == sizeof (int))
+    return ffs (i);
+  else
+    {
+      unsigned TYPE j = i;
+      /* Split j into chunks, and look at one chunk after the other.  */
+      /* Define chunk_bits so as to avoid a GCC warning
+           "right shift count >= width of type"
+         if sizeof (TYPE) == sizeof (int).  */
+      enum
+        {
+          chunk_bits = (sizeof (TYPE) != sizeof (int)
+                        ? CHAR_BIT * sizeof (unsigned int)
+                        : 0)
+        };
+      int result = 0;
 
-  /* GCC has __builtin_ffs, but it is limited to int.  */
-  if (!i)
-    return 0;
-  while (1)
-    {
-      if ((unsigned int) j)
-        return result + ffs ((unsigned int) j);
-      j >>= CHAR_BIT * sizeof (unsigned int);
-      result += CHAR_BIT * sizeof (unsigned int);
+      /* It is tempting to write  if (!j)  here, but if we do this,
+         Solaris 10/x86 "cc -O" miscompiles the code.  */
+      if (!i)
+        return 0;
+      while (1)
+        {
+          if ((unsigned int) j)
+            return result + ffs ((unsigned int) j);
+          j >>= chunk_bits;
+          result += chunk_bits;
+        }
     }
 #endif
 }