toplev.c (floor_log2_wide): Replace loop with faster bit operations.
authorDJ Delorie <dj@redhat.com>
Tue, 8 Jun 2004 19:24:07 +0000 (15:24 -0400)
committerDJ Delorie <dj@gcc.gnu.org>
Tue, 8 Jun 2004 19:24:07 +0000 (15:24 -0400)
* toplev.c (floor_log2_wide): Replace loop with faster bit
operations.
(exact_log2_wide): Define in terms of the above.
* toplev.h (floor_log2): Use _builtin_clz family of builtins if
available.

From-SVN: r82778

gcc/ChangeLog
gcc/toplev.c
gcc/toplev.h

index b251c45ad0c8ee8790d9969a1f58fa887bbdb2a0..d150c60822dae09791cc6aa5b36284a22977779c 100644 (file)
@@ -1,3 +1,11 @@
+2004-06-08  DJ Delorie  <dj@redhat.com>
+
+       * toplev.c (floor_log2_wide): Replace loop with faster bit
+       operations.
+       (exact_log2_wide): Define in terms of the above.
+       * toplev.h (floor_log2): Use _builtin_clz family of builtins if
+       available.
+
 2004-06-08  Andrew Pinski  <pinskia@physics.uc.edu>
 
        * config/rs6000/rs6000.c (print_operand, <case 'z'>):
index 2741be5047fd8d169caced4dd84911eda80ee95a..e1803943d9c509ac898c452403fb74e9fb03670c 100644 (file)
@@ -1248,36 +1248,48 @@ read_integral_parameter (const char *p, const char *pname, const int  defval)
   return atoi (p);
 }
 
-/* Return the logarithm of X, base 2, considering X unsigned,
-   if X is a power of 2.  Otherwise, returns -1.
+/* Given X, an unsigned number, return the largest int Y such that 2**Y <= X.
+   If X is 0, return -1.
 
-   This should be used via the `exact_log2' macro.  */
+   This should be used via the floor_log2 macro.  */
 
 int
-exact_log2_wide (unsigned HOST_WIDE_INT x)
+floor_log2_wide (unsigned HOST_WIDE_INT x)
 {
-  int log = 0;
-  /* Test for 0 or a power of 2.  */
-  if (x == 0 || x != (x & -x))
+  int t=0;
+  if (x == 0)
     return -1;
-  while ((x >>= 1) != 0)
-    log++;
-  return log;
+  if (sizeof (HOST_WIDE_INT)*8 > 64)
+    if (x >= (unsigned HOST_WIDE_INT)(1 << (t+64)))
+      t += 64;
+  if (sizeof (HOST_WIDE_INT)*8 > 32)
+    if (x >= (unsigned HOST_WIDE_INT)(1 << (t+32)))
+      t += 32;
+  if (x >= (unsigned HOST_WIDE_INT)(1 << (t+16)))
+    t += 16;
+  if (x >= (unsigned HOST_WIDE_INT)(1 << (t+8)))
+    t += 8;
+  if (x >= (unsigned HOST_WIDE_INT)(1 << (t+4)))
+    t += 4;
+  if (x >= (unsigned HOST_WIDE_INT)(1 << (t+2)))
+    t += 2;
+  if (x >= (unsigned HOST_WIDE_INT)(1 << (t+1)))
+    t += 1;
+  return t;
 }
 
-/* Given X, an unsigned number, return the largest int Y such that 2**Y <= X.
-   If X is 0, return -1.
+/* Return the logarithm of X, base 2, considering X unsigned,
+   if X is a power of 2.  Otherwise, returns -1.
 
-   This should be used via the floor_log2 macro.  */
+   This should be used via the `exact_log2' macro.  */
 
 int
-floor_log2_wide (unsigned HOST_WIDE_INT x)
+exact_log2_wide (unsigned HOST_WIDE_INT x)
 {
-  int log = -1;
-  while (x != 0)
-    log++,
-    x >>= 1;
-  return log;
+  /* Test for 0 or a power of 2.  */
+  if (x == 0 || x != (x & -x))
+    return -1;
+  return floor_log2_wide (x);
 }
 
 /* Handler for fatal signals, such as SIGSEGV.  These are transformed
index aca355771fb02df2518ce480be14df6acfe0f373..f12102e9f7b46a00c745661a0f7ee147f40ee820 100644 (file)
@@ -152,7 +152,30 @@ extern bool fast_math_flags_set_p  (void);
 
 #ifndef exact_log2
 #define exact_log2(N) exact_log2_wide ((unsigned HOST_WIDE_INT) (N))
+
+#if (__GNUC__ * 1000 + __GNUC_MINOR__) >= 3004
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONGLONG
+#define FL2T__ HOST_WIDE_INT
+#define FL2T_CLZ__ __builtin_clzll
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
+#define FL2T__ HOST_WIDE_INT
+#define FL2T_CLZ__ __builtin_clzl
+#else
+#define FL2T__ int
+#define FL2T_CLZ__ __builtin_clz
+#endif
+#endif
+static inline int floor_log2(FL2T__ n)
+{
+  if (n)
+    return (sizeof(FL2T__)*8-1) - (int)FL2T_CLZ__(n);
+  return -1;
+}
+#else
 #define floor_log2(N) floor_log2_wide ((unsigned HOST_WIDE_INT) (N))
+#endif
+
 #endif
 extern int exact_log2_wide             (unsigned HOST_WIDE_INT);
 extern int floor_log2_wide             (unsigned HOST_WIDE_INT);