2005-12-04 Joseph S. Myers <joseph@codesourcery.com>
[kopensolaris-gnu/glibc.git] / soft-fp / op-common.h
index 012e76f..46162ed 100644 (file)
@@ -1,5 +1,5 @@
 /* Software floating-point emulation. Common operations.
-   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   Copyright (C) 1997,1998,1999,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Richard Henderson (rth@cygnus.com),
                  Jakub Jelinek (jj@ultra.linux.cz),
@@ -89,11 +89,10 @@ do {                                                                \
        _FP_ROUND(wc, X);                                       \
        if (_FP_FRAC_OVERP_##wc(fs, X))                         \
          {                                                     \
-           _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1));             \
+           _FP_FRAC_CLEAR_OVERP_##wc(fs, X);                   \
            X##_e++;                                            \
          }                                                     \
-       else                                                    \
-         _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);                   \
+       _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);                     \
        if (X##_e >= _FP_EXPMAX_##fs)                           \
          {                                                     \
            /* overflow */                                      \
@@ -682,25 +681,27 @@ do {                                                                      \
   do {                                                                 \
     if (r)                                                             \
       {                                                                        \
+        unsigned rtype ur_;                                            \
        X##_c = FP_CLS_NORMAL;                                          \
                                                                        \
        if ((X##_s = (r < 0)))                                          \
          r = -r;                                                       \
                                                                        \
+       ur_ = (unsigned rtype) r;                                       \
        if (rsize <= _FP_W_TYPE_SIZE)                                   \
-         __FP_CLZ(X##_e, r);                                           \
+         __FP_CLZ(X##_e, ur_);                                         \
        else                                                            \
-         __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE),         \
-                    (_FP_W_TYPE)r);                                    \
+         __FP_CLZ_2(X##_e, (_FP_W_TYPE)(ur_ >> _FP_W_TYPE_SIZE),       \
+                    (_FP_W_TYPE)ur_);                                  \
        if (rsize < _FP_W_TYPE_SIZE)                                    \
                X##_e -= (_FP_W_TYPE_SIZE - rsize);                     \
        X##_e = rsize - X##_e - 1;                                      \
                                                                        \
        if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)    \
-         __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize);      \
-       r &= ~((rtype)1 << X##_e);                                      \
-       _FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize);       \
-       _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));         \
+         __FP_FRAC_SRS_1(ur_, (X##_e - _FP_WFRACBITS_##fs + 1), rsize);\
+       _FP_FRAC_DISASSEMBLE_##wc(X, ur_, rsize);                       \
+       if ((_FP_WFRACBITS_##fs - X##_e - 1) > 0)                       \
+         _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));       \
       }                                                                        \
     else                                                               \
       {                                                                        \
@@ -724,40 +725,18 @@ do {                                                                      \
 /* Count leading zeros in a word.  */
 
 #ifndef __FP_CLZ
-#if _FP_W_TYPE_SIZE < 64
-/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */
-#define __FP_CLZ(r, x)                         \
-  do {                                         \
-    _FP_W_TYPE _t = (x);                       \
-    r = _FP_W_TYPE_SIZE - 1;                   \
-    if (_t > 0xffff) r -= 16;                  \
-    if (_t > 0xffff) _t >>= 16;                        \
-    if (_t > 0xff) r -= 8;                     \
-    if (_t > 0xff) _t >>= 8;                   \
-    if (_t & 0xf0) r -= 4;                     \
-    if (_t & 0xf0) _t >>= 4;                   \
-    if (_t & 0xc) r -= 2;                      \
-    if (_t & 0xc) _t >>= 2;                    \
-    if (_t & 0x2) r -= 1;                      \
-  } while (0)
-#else /* not _FP_W_TYPE_SIZE < 64 */
-#define __FP_CLZ(r, x)                         \
-  do {                                         \
-    _FP_W_TYPE _t = (x);                       \
-    r = _FP_W_TYPE_SIZE - 1;                   \
-    if (_t > 0xffffffff) r -= 32;              \
-    if (_t > 0xffffffff) _t >>= 32;            \
-    if (_t > 0xffff) r -= 16;                  \
-    if (_t > 0xffff) _t >>= 16;                        \
-    if (_t > 0xff) r -= 8;                     \
-    if (_t > 0xff) _t >>= 8;                   \
-    if (_t & 0xf0) r -= 4;                     \
-    if (_t & 0xf0) _t >>= 4;                   \
-    if (_t & 0xc) r -= 2;                      \
-    if (_t & 0xc) _t >>= 2;                    \
-    if (_t & 0x2) r -= 1;                      \
+/* GCC 3.4 and later provide the builtins for us.  */
+#define __FP_CLZ(r, x)                                                       \
+  do {                                                                       \
+    if (sizeof (_FP_W_TYPE) == sizeof (unsigned int))                        \
+      r = __builtin_clz (x);                                                 \
+    else if (sizeof (_FP_W_TYPE) == sizeof (unsigned long))                  \
+      r = __builtin_clzl (x);                                                \
+    else if (sizeof (_FP_W_TYPE) == sizeof (unsigned long long))             \
+      r = __builtin_clzll (x);                                               \
+    else                                                                     \
+      abort ();                                                                      \
   } while (0)
-#endif /* not _FP_W_TYPE_SIZE < 64 */
 #endif /* ndef __FP_CLZ */
 
 #define _FP_DIV_HELP_imm(q, r, n, d)           \
@@ -765,3 +744,47 @@ do {                                                                       \
     q = n / d, r = n % d;                      \
   } while (0)
 
+
+/* A restoring bit-by-bit division primitive.  */
+
+#define _FP_DIV_MEAT_N_loop(fs, wc, R, X, Y)                           \
+  do {                                                                 \
+    int count = _FP_WFRACBITS_##fs;                                    \
+    _FP_FRAC_DECL_##wc (u);                                            \
+    _FP_FRAC_DECL_##wc (v);                                            \
+    _FP_FRAC_COPY_##wc (u, X);                                         \
+    _FP_FRAC_COPY_##wc (v, Y);                                         \
+    _FP_FRAC_SET_##wc (R, _FP_ZEROFRAC_##wc);                          \
+    /* Normalize U and V.  */                                          \
+    _FP_FRAC_SLL_##wc (u, _FP_WFRACXBITS_##fs);                                \
+    _FP_FRAC_SLL_##wc (v, _FP_WFRACXBITS_##fs);                                \
+    /* First round.  Since the operands are normalized, either the     \
+       first or second bit will be set in the fraction.  Produce a     \
+       normalized result by checking which and adjusting the loop      \
+       count and exponent accordingly.  */                             \
+    if (_FP_FRAC_GE_1 (u, v))                                          \
+      {                                                                        \
+       _FP_FRAC_SUB_##wc (u, u, v);                                    \
+       _FP_FRAC_LOW_##wc (R) |= 1;                                     \
+       count--;                                                        \
+      }                                                                        \
+    else                                                               \
+      R##_e--;                                                         \
+    /* Subsequent rounds.  */                                          \
+    do {                                                               \
+      int msb = (_FP_WS_TYPE) _FP_FRAC_HIGH_##wc (u) < 0;              \
+      _FP_FRAC_SLL_##wc (u, 1);                                                \
+      _FP_FRAC_SLL_##wc (R, 1);                                                \
+      if (msb || _FP_FRAC_GE_1 (u, v))                                 \
+       {                                                               \
+         _FP_FRAC_SUB_##wc (u, u, v);                                  \
+         _FP_FRAC_LOW_##wc (R) |= 1;                                   \
+       }                                                               \
+    } while (--count > 0);                                             \
+    /* If there's anything left in U, the result is inexact.  */       \
+    _FP_FRAC_LOW_##wc (R) |= !_FP_FRAC_ZEROP_##wc (u);                 \
+  } while (0)
+
+#define _FP_DIV_MEAT_1_loop(fs, R, X, Y)  _FP_DIV_MEAT_N_loop (fs, 1, R, X, Y)
+#define _FP_DIV_MEAT_2_loop(fs, R, X, Y)  _FP_DIV_MEAT_N_loop (fs, 2, R, X, Y)
+#define _FP_DIV_MEAT_4_loop(fs, R, X, Y)  _FP_DIV_MEAT_N_loop (fs, 4, R, X, Y)