summaryrefslogtreecommitdiff
path: root/longlong.h
diff options
context:
space:
mode:
authorTorbjorn Granlund <tege@gmplib.org>2012-03-19 00:06:51 +0100
committerTorbjorn Granlund <tege@gmplib.org>2012-03-19 00:06:51 +0100
commita96ddf53dd99f15f31327233b174769d686f4661 (patch)
tree2f6b95031ed11a71133d6fed6b3ce783d5882fb4 /longlong.h
parent693e7672173d377a00b26367696c148b89422fa5 (diff)
downloadgmp-a96ddf53dd99f15f31327233b174769d686f4661.tar.gz
(count_trailing_zeros): Write better pure C default variant.
Diffstat (limited to 'longlong.h')
-rw-r--r--longlong.h31
1 files changed, 28 insertions, 3 deletions
diff --git a/longlong.h b/longlong.h
index 5b65c1500..e83206011 100644
--- a/longlong.h
+++ b/longlong.h
@@ -2050,6 +2050,7 @@ __GMP_DECLSPEC UWtype __MPN(udiv_w_sdiv) (UWtype *, UWtype, UWtype, UWtype);
/* This version gives a well-defined value for zero. */
#define COUNT_LEADING_ZEROS_0 (W_TYPE_SIZE - 1)
#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#define COUNT_LEADING_ZEROS_SLOW
#endif
/* clz_tab needed by mpn/x86/pentium/mod_1.asm in a fat binary */
@@ -2062,9 +2063,9 @@ extern const unsigned char __GMP_DECLSPEC __clz_tab[128];
#endif
#if !defined (count_trailing_zeros)
-/* Define count_trailing_zeros using count_leading_zeros. The latter might be
- defined in asm, but if it is not, the C version above is good enough. */
-#define count_trailing_zeros(count, x) \
+#if !defined (COUNT_LEADING_ZEROS_SLOW)
+/* Define count_trailing_zeros using an asm count_leading_zeros. */
+#define count_trailing_zeros(count, x) \
do { \
UWtype __ctz_x = (x); \
UWtype __ctz_c; \
@@ -2072,6 +2073,30 @@ extern const unsigned char __GMP_DECLSPEC __clz_tab[128];
count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \
(count) = W_TYPE_SIZE - 1 - __ctz_c; \
} while (0)
+#else
+/* Define count_trailing_zeros in plain C, assuming small counts are common.
+ We use clz_tab without ado, since the C count_leading_zeros above will have
+ pulled it in. */
+#define count_trailing_zeros(count, x) \
+ do { \
+ UWtype __ctz_x = (x); \
+ int __ctz_c; \
+ \
+ if (LIKELY ((__ctz_x & 0x7f) != 0)) \
+ (count) = __clz_tab[__ctz_x & -__ctz_x] - 2; \
+ else \
+ { \
+ for (__ctz_c = 5; __ctz_c <= W_TYPE_SIZE; __ctz_c += 7) \
+ { \
+ __ctz_x >>= 7; \
+ if (LIKELY ((__ctz_x & 0x7f) != 0)) \
+ break; \
+ } \
+ \
+ (count) = __ctz_c + __clz_tab[__ctz_x & -__ctz_x]; \
+ } \
+ } while (0)
+#endif
#endif
#ifndef UDIV_NEEDS_NORMALIZATION