From: Bruno Haible <bruno@clisp.org>
Date: Fri, 14 Oct 2011 00:11:34 +0000 (+0200)
Subject: ffsl: Optimize on 32-bit platforms.
X-Git-Tag: v0.1~1579
X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=22950665cce29d2350b45fc0a255ffec847e12da;p=gnulib.git

ffsl: Optimize on 32-bit platforms.

* lib/ffsl.h (FUNC): If TYPE has the same representation as 'int', just
use ffs() without a loop.
---

diff --git a/ChangeLog b/ChangeLog
index 866dfa293d..fede05e012 100644
--- 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.
diff --git a/lib/ffsl.h b/lib/ffsl.h
index 9f209123d9..99e7d264ac 100644
--- a/lib/ffsl.h
+++ b/lib/ffsl.h
@@ -34,18 +34,34 @@ FUNC (TYPE i)
 #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined GCC_BUILTIN
   return GCC_BUILTIN (i);
 #else
-  int result = 0;
-  unsigned TYPE j = i;
-
-  /* GCC has __builtin_ffs, but it is limited to int.  */
-  if (!i)
-    return 0;
-  while (1)
+  if (sizeof (TYPE) == sizeof (int))
+    return ffs (i);
+  else
     {
-      if ((unsigned int) j)
-        return result + ffs ((unsigned int) j);
-      j >>= CHAR_BIT * sizeof (unsigned int);
-      result += CHAR_BIT * sizeof (unsigned int);
+      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;
+
+      /* 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
 }