]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
soft-fp: Support rsigned == 2 in _FP_TO_INT.
authorJoseph Myers <joseph@codesourcery.com>
Thu, 9 Oct 2014 15:00:37 +0000 (15:00 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Thu, 9 Oct 2014 15:00:37 +0000 (15:00 +0000)
Continuing the addition of soft-fp features in the Linux kernel
version, this patch adds _FP_TO_INT support for rsigned == 2 (reduce
overflowing results modulo 2^rsize to fit in the destination, used for
alpha emulation).

The kernel version is buggy; it can left shift by a negative amount
when right shifting is required in an overflow case (the kernel
version also has other bugs fixed long ago in glibc; at least,
spurious exceptions converting to the most negative integer).  This
version avoids that by handling overflow (other than to 0) for rsigned
== 2 along with the normal non-overflow case, which already properly
determines the direction in which to shift.

Tested for powerpc-nofpu.  Some functions get slightly bigger and some
get slightly smaller, no doubt as a result of the change to where in
the macro "inexact" is raised, but I don't think those changes are
significant.  Also tested for powerpc-nofpu with the relevant __fix*
functions changed to use rsigned == 2 (which is after all just as
valid as rsigned == 1 in IEEE terms), including verifying the results
and exceptions for various cases of conversions.

With these seven patches, the one remaining feature to add for the
soft-fp code to have all the features of the kernel version is
_FP_TO_INT_ROUND.

* soft-fp/op-common.h (_FP_TO_INT): Handle rsigned == 2.

ChangeLog
soft-fp/op-common.h

index fa354c23349f82d6654cb9451c23b1fb8ec59aa2..f8f2221d7c08168f168c90adbc9496a680cd0e2c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
 2014-10-09  Joseph Myers  <joseph@codesourcery.com>
 
+       * soft-fp/op-common.h (_FP_TO_INT): Handle rsigned == 2.
+
        * soft-fp/soft-fp.h (FP_EX_INVALID_SNAN): New macro.
        (FP_EX_INVALID_IMZ): Likewise.
        (FP_EX_INVALID_IMZ_FMA): Likewise.
index 8344be5aadd4fee67f60970a77960461bee15afb..3591c47efbfc835f4f828467282739089f103720 100644 (file)
    1:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not,
        NV is set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1
        depending on the sign in such case.
+   2:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not,
+       NV is set plus the result is reduced modulo 2^rsize.
    -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is
        set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1
        depending on the sign in such case.  */
          else                                                          \
            FP_SET_EXCEPTION (FP_EX_INEXACT);                           \
        }                                                               \
-      else if (X##_e >= (_FP_EXPMAX_##fs < _FP_EXPBIAS_##fs + rsize    \
-                        ? _FP_EXPMAX_##fs                              \
-                        : _FP_EXPBIAS_##fs + rsize - (rsigned > 0 || X##_s)) \
-              || (!rsigned && X##_s))                                  \
+      else if (rsigned == 2                                            \
+              && (X##_e                                                \
+                  >= ((_FP_EXPMAX_##fs                                 \
+                       < _FP_EXPBIAS_##fs + _FP_FRACBITS_##fs + rsize - 1) \
+                      ? _FP_EXPMAX_##fs                                \
+                      : _FP_EXPBIAS_##fs + _FP_FRACBITS_##fs + rsize - 1))) \
+       {                                                               \
+         /* Overflow resulting in 0.  */                               \
+         r = 0;                                                        \
+         FP_SET_EXCEPTION (FP_EX_INVALID                               \
+                           | FP_EX_INVALID_CVI                         \
+                           | ((FP_EX_INVALID_SNAN                      \
+                               && _FP_ISSIGNAN (fs, wc, X))            \
+                              ? FP_EX_INVALID_SNAN                     \
+                              : 0));                                   \
+       }                                                               \
+      else if (rsigned != 2                                            \
+              && (X##_e >= (_FP_EXPMAX_##fs < _FP_EXPBIAS_##fs + rsize \
+                            ? _FP_EXPMAX_##fs                          \
+                            : (_FP_EXPBIAS_##fs + rsize                \
+                               - (rsigned > 0 || X##_s)))              \
+                  || (!rsigned && X##_s)))                             \
        {                                                               \
          /* Overflow or converting to the most negative integer.  */   \
          if (rsigned)                                                  \
        }                                                               \
       else                                                             \
        {                                                               \
+         int _FP_TO_INT_inexact = 0;                                   \
          _FP_FRAC_HIGH_RAW_##fs (X) |= _FP_IMPLBIT_##fs;               \
          if (X##_e >= _FP_EXPBIAS_##fs + _FP_FRACBITS_##fs - 1)        \
            {                                                           \
            }                                                           \
          else                                                          \
            {                                                           \
-             int _FP_TO_INT_inexact;                                   \
              _FP_FRAC_SRST_##wc (X, _FP_TO_INT_inexact,                \
                                  (_FP_FRACBITS_##fs + _FP_EXPBIAS_##fs - 1 \
                                   - X##_e),                            \
                                  _FP_FRACBITS_##fs);                   \
-             if (_FP_TO_INT_inexact)                                   \
-               FP_SET_EXCEPTION (FP_EX_INEXACT);                       \
              _FP_FRAC_ASSEMBLE_##wc (r, X, rsize);                     \
            }                                                           \
          if (rsigned && X##_s)                                         \
            r = -r;                                                     \
+         if (rsigned == 2 && X##_e >= _FP_EXPBIAS_##fs + rsize - 1)    \
+           {                                                           \
+             /* Overflow or converting to the most negative integer.  */ \
+             if (X##_e > _FP_EXPBIAS_##fs + rsize - 1                  \
+                 || !X##_s                                             \
+                 || r != (((typeof (r)) 1) << (rsize - 1)))            \
+               {                                                       \
+                 _FP_TO_INT_inexact = 0;                               \
+                 FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_CVI); \
+               }                                                       \
+           }                                                           \
+         if (_FP_TO_INT_inexact)                                       \
+           FP_SET_EXCEPTION (FP_EX_INEXACT);                           \
        }                                                               \
     }                                                                  \
   while (0)