summaryrefslogtreecommitdiff
path: root/longlong.h
diff options
context:
space:
mode:
authorKevin Ryde <user42@zip.com.au>2004-02-28 22:28:11 +0100
committerKevin Ryde <user42@zip.com.au>2004-02-28 22:28:11 +0100
commit15a29e66e57ee5553dc7a378d9b9dab807a96119 (patch)
tree57539c45beb3892de4307d120809ce8bda705930 /longlong.h
parent0d86f77e2ca976e2ccf4a31432778a29d75d6acf (diff)
downloadgmp-15a29e66e57ee5553dc7a378d9b9dab807a96119.tar.gz
* longlong.h (count_leading_zeros) [alpha gcc]: New version, inlining
mpn/alpha/cntlz.asm cmpbge technique.
Diffstat (limited to 'longlong.h')
-rw-r--r--longlong.h39
1 files changed, 33 insertions, 6 deletions
diff --git a/longlong.h b/longlong.h
index b5627659f..2337cc940 100644
--- a/longlong.h
+++ b/longlong.h
@@ -154,16 +154,44 @@ MA 02111-1307, USA. */
#define UDIV_NEEDS_NORMALIZATION 1
#define UDIV_TIME 220
#endif /* LONGLONG_STANDALONE */
-/* clz_tab is required by mpn/alpha/cntlz.asm, and that file is built for
- all alphas, even though CIX chips don't need it. */
+
+/* clz_tab is required in all configurations, since mpn/alpha/cntlz.asm
+ always goes into libgmp.so, even when not actually used. */
#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+
#if defined (__GNUC__) && HAVE_HOST_CPU_alpha_CIX
#define count_leading_zeros(COUNT,X) \
__asm__("ctlz %1,%0" : "=r"(COUNT) : "r"(X))
#define count_trailing_zeros(COUNT,X) \
__asm__("cttz %1,%0" : "=r"(COUNT) : "r"(X))
-#else /* ! CIX */
-#ifndef LONGLONG_STANDALONE
+#endif /* clz/ctz using cix */
+
+#if ! defined (count_leading_zeros) \
+ && defined (__GNUC__) && ! defined (LONGLONG_STANDALONE)
+/* ALPHA_CMPBGE_0 gives "cmpbge $31,src,dst", ie. test src bytes == 0.
+ "$31" is written explicitly in the asm, since an "r" constraint won't
+ select reg 31. There seems no need to worry about "r31" syntax for cray,
+ since gcc itself (pre-release 3.4) emits just $31 in various places. */
+#define ALPHA_CMPBGE_0(dst, src) \
+ do { asm ("cmpbge $31, %1, %0" : "=r" (dst) : "r" (src)); } while (0)
+/* Zero bytes are turned into bits with cmpbge, a __clz_tab lookup counts
+ them, locating the highest non-zero byte. A second __clz_tab lookup
+ counts the leading zero bits in that byte, giving the result. */
+#define count_leading_zeros(count, x) \
+ do { \
+ UWtype __clz__b, __clz__c, __clz__x = (x); \
+ ALPHA_CMPBGE_0 (__clz__b, __clz__x); /* zero bytes */ \
+ __clz__b = __clz_tab [(__clz__b >> 1) ^ 0x7F]; /* 8 to 1 byte */ \
+ __clz__b = __clz__b * 8 - 7; /* 57 to 1 shift */ \
+ __clz__x >>= __clz__b; \
+ __clz__c = __clz_tab [__clz__x]; /* 8 to 1 bit */ \
+ __clz__b = 65 - __clz__b; \
+ (count) = __clz__b - __clz__c; \
+ } while (0)
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#endif /* clz using cmpbge */
+
+#if ! defined (count_leading_zeros) && ! defined (LONGLONG_STANDALONE)
#if HAVE_ATTRIBUTE_CONST
long __MPN(count_leading_zeros) _PROTO ((UDItype)) __attribute__ ((const));
#else
@@ -171,8 +199,7 @@ long __MPN(count_leading_zeros) _PROTO ((UDItype));
#endif
#define count_leading_zeros(count, x) \
((count) = __MPN(count_leading_zeros) (x))
-#endif /* LONGLONG_STANDALONE */
-#endif /* ! CIX */
+#endif /* clz using mpn */
#endif /* __alpha */
#if defined (_CRAY) && W_TYPE_SIZE == 64