diff options
author | Kevin Ryde <user42@zip.com.au> | 2004-02-28 22:28:11 +0100 |
---|---|---|
committer | Kevin Ryde <user42@zip.com.au> | 2004-02-28 22:28:11 +0100 |
commit | 15a29e66e57ee5553dc7a378d9b9dab807a96119 (patch) | |
tree | 57539c45beb3892de4307d120809ce8bda705930 /longlong.h | |
parent | 0d86f77e2ca976e2ccf4a31432778a29d75d6acf (diff) | |
download | gmp-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.h | 39 |
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 |