[Qemu-devel] [PATCH v2] softfloat: Support float_round_to_odd more places

Richard Henderson posted 1 patch 5 years, 1 month ago
Test asan passed
Test docker-clang@ubuntu failed
Test docker-mingw@fedora passed
Test checkpatch passed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20190215170225.15537-1-richard.henderson@linaro.org
Maintainers: Aurelien Jarno <aurelien@aurel32.net>, Peter Maydell <peter.maydell@linaro.org>, "Alex Bennée" <alex.bennee@linaro.org>
fpu/softfloat.c    | 64 ++++++++++++++++++++++++++++++++++++++++++----
tests/fp/fp-test.c | 43 ++++++++++++++++++++++++-------
2 files changed, 93 insertions(+), 14 deletions(-)
[Qemu-devel] [PATCH v2] softfloat: Support float_round_to_odd more places
Posted by Richard Henderson 5 years, 1 month ago
Previously this was only supported for roundAndPackFloat64.

New support in round_canonical, round_to_int, float128_round_to_int,
roundAndPackFloat32, roundAndPackInt32, roundAndPackInt64,
roundAndPackUint64.  This does not include any of the floatx80 routines,
as we do not have users for that rounding mode there.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
v2: Convert float128_round_to_int as well.  Add fp-test support.
---
 fpu/softfloat.c    | 64 ++++++++++++++++++++++++++++++++++++++++++----
 tests/fp/fp-test.c | 43 ++++++++++++++++++++++++-------
 2 files changed, 93 insertions(+), 14 deletions(-)

diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 9132d7a0b0..76132d4cd5 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -696,6 +696,7 @@ static FloatParts sf_canonicalize(FloatParts part, const FloatFmt *parm,
 static FloatParts round_canonical(FloatParts p, float_status *s,
                                   const FloatFmt *parm)
 {
+    const uint64_t frac_lsb = parm->frac_lsb;
     const uint64_t frac_lsbm1 = parm->frac_lsbm1;
     const uint64_t round_mask = parm->round_mask;
     const uint64_t roundeven_mask = parm->roundeven_mask;
@@ -731,6 +732,10 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
             inc = p.sign ? round_mask : 0;
             overflow_norm = !p.sign;
             break;
+        case float_round_to_odd:
+            overflow_norm = true;
+            inc = frac & frac_lsb ? 0 : round_mask;
+            break;
         default:
             g_assert_not_reached();
         }
@@ -778,9 +783,14 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
             shift64RightJamming(frac, 1 - exp, &frac);
             if (frac & round_mask) {
                 /* Need to recompute round-to-even.  */
-                if (s->float_rounding_mode == float_round_nearest_even) {
+                switch (s->float_rounding_mode) {
+                case float_round_nearest_even:
                     inc = ((frac & roundeven_mask) != frac_lsbm1
                            ? frac_lsbm1 : 0);
+                    break;
+                case float_round_to_odd:
+                    inc = frac & frac_lsb ? 0 : round_mask;
+                    break;
                 }
                 flags |= float_flag_inexact;
                 frac += inc;
@@ -1988,6 +1998,9 @@ static FloatParts round_to_int(FloatParts a, int rmode,
             case float_round_down:
                 one = a.sign;
                 break;
+            case float_round_to_odd:
+                one = true;
+                break;
             default:
                 g_assert_not_reached();
             }
@@ -2021,6 +2034,9 @@ static FloatParts round_to_int(FloatParts a, int rmode,
             case float_round_down:
                 inc = a.sign ? rnd_mask : 0;
                 break;
+            case float_round_to_odd:
+                inc = a.frac & frac_lsb ? 0 : rnd_mask;
+                break;
             default:
                 g_assert_not_reached();
             }
@@ -3314,6 +3330,9 @@ static int32_t roundAndPackInt32(flag zSign, uint64_t absZ, float_status *status
     case float_round_down:
         roundIncrement = zSign ? 0x7f : 0;
         break;
+    case float_round_to_odd:
+        roundIncrement = absZ & 0x80 ? 0 : 0x7f;
+        break;
     default:
         abort();
     }
@@ -3368,6 +3387,9 @@ static int64_t roundAndPackInt64(flag zSign, uint64_t absZ0, uint64_t absZ1,
     case float_round_down:
         increment = zSign && absZ1;
         break;
+    case float_round_to_odd:
+        increment = !(absZ0 & 1) && absZ1;
+        break;
     default:
         abort();
     }
@@ -3424,6 +3446,9 @@ static int64_t roundAndPackUint64(flag zSign, uint64_t absZ0,
     case float_round_down:
         increment = zSign && absZ1;
         break;
+    case float_round_to_odd:
+        increment = !(absZ0 & 1) && absZ1;
+        break;
     default:
         abort();
     }
@@ -3526,6 +3551,8 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
     case float_round_down:
         roundIncrement = zSign ? 0x7f : 0;
         break;
+    case float_round_to_odd:
+        roundIncrement = zSig & 0x80 ? 0 : 0x7f;
     default:
         abort();
         break;
@@ -3536,8 +3563,10 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
              || (    ( zExp == 0xFD )
                   && ( (int32_t) ( zSig + roundIncrement ) < 0 ) )
            ) {
+            bool overflow_to_inf = roundingMode != float_round_to_odd &&
+                                   roundIncrement != 0;
             float_raise(float_flag_overflow | float_flag_inexact, status);
-            return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
+            return packFloat32(zSign, 0xFF, -!overflow_to_inf);
         }
         if ( zExp < 0 ) {
             if (status->flush_to_zero) {
@@ -3555,6 +3584,13 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
             if (isTiny && roundBits) {
                 float_raise(float_flag_underflow, status);
             }
+            if (roundingMode == float_round_to_odd) {
+                /*
+                 * For round-to-odd case, the roundIncrement depends on
+                 * zSig which just changed.
+                 */
+                roundIncrement = zSig & 0x80 ? 0 : 0x7f;
+            }
         }
     }
     if (roundBits) {
@@ -6958,6 +6994,15 @@ float128 float128_round_to_int(float128 a, float_status *status)
                 add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low);
             }
             break;
+        case float_round_to_odd:
+            /*
+             * Note that if lastBitMask == 0, the last bit is the lsb
+             * of high, and roundBitsMask == -1.
+             */
+            if ((lastBitMask ? z.low & lastBitMask : z.high & 1) == 0) {
+                add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low);
+            }
+            break;
         default:
             abort();
         }
@@ -6969,7 +7014,7 @@ float128 float128_round_to_int(float128 a, float_status *status)
             status->float_exception_flags |= float_flag_inexact;
             aSign = extractFloat128Sign( a );
             switch (status->float_rounding_mode) {
-             case float_round_nearest_even:
+            case float_round_nearest_even:
                 if (    ( aExp == 0x3FFE )
                      && (   extractFloat128Frac0( a )
                           | extractFloat128Frac1( a ) )
@@ -6982,14 +7027,17 @@ float128 float128_round_to_int(float128 a, float_status *status)
                     return packFloat128(aSign, 0x3FFF, 0, 0);
                 }
                 break;
-             case float_round_down:
+            case float_round_down:
                 return
                       aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
                     : packFloat128( 0, 0, 0, 0 );
-             case float_round_up:
+            case float_round_up:
                 return
                       aSign ? packFloat128( 1, 0, 0, 0 )
                     : packFloat128( 0, 0x3FFF, 0, 0 );
+
+            case float_round_to_odd:
+                return packFloat128(aSign, 0x3FFF, 0, 0);
             }
             return packFloat128( aSign, 0, 0, 0 );
         }
@@ -7022,6 +7070,12 @@ float128 float128_round_to_int(float128 a, float_status *status)
                 z.high += roundBitsMask;
             }
             break;
+        case float_round_to_odd:
+            if ((z.high & lastBitMask) == 0) {
+                z.high |= (a.low != 0);
+                z.high += roundBitsMask;
+            }
+            break;
         default:
             abort();
         }
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
index 2a35ef601d..471adb862d 100644
--- a/tests/fp/fp-test.c
+++ b/tests/fp/fp-test.c
@@ -125,17 +125,42 @@ static void not_implemented(void)
 
 static bool blacklisted(unsigned op, int rmode)
 {
-    /* odd has only been implemented for a few 128-bit ops */
+    /* odd has not been implemented for any 80-bit ops */
     if (rmode == softfloat_round_odd) {
         switch (op) {
-        case F128_ADD:
-        case F128_SUB:
-        case F128_MUL:
-        case F128_DIV:
-        case F128_TO_F64:
-        case F128_SQRT:
-            return false;
-        default:
+        case EXTF80_TO_UI32:
+        case EXTF80_TO_UI64:
+        case EXTF80_TO_I32:
+        case EXTF80_TO_I64:
+        case EXTF80_TO_UI32_R_MINMAG:
+        case EXTF80_TO_UI64_R_MINMAG:
+        case EXTF80_TO_I32_R_MINMAG:
+        case EXTF80_TO_I64_R_MINMAG:
+        case EXTF80_TO_F16:
+        case EXTF80_TO_F32:
+        case EXTF80_TO_F64:
+        case EXTF80_TO_F128:
+        case EXTF80_ROUNDTOINT:
+        case EXTF80_ADD:
+        case EXTF80_SUB:
+        case EXTF80_MUL:
+        case EXTF80_DIV:
+        case EXTF80_REM:
+        case EXTF80_SQRT:
+        case EXTF80_EQ:
+        case EXTF80_LE:
+        case EXTF80_LT:
+        case EXTF80_EQ_SIGNALING:
+        case EXTF80_LE_QUIET:
+        case EXTF80_LT_QUIET:
+        case UI32_TO_EXTF80:
+        case UI64_TO_EXTF80:
+        case I32_TO_EXTF80:
+        case I64_TO_EXTF80:
+        case F16_TO_EXTF80:
+        case F32_TO_EXTF80:
+        case F64_TO_EXTF80:
+        case F128_TO_EXTF80:
             return true;
         }
     }
-- 
2.17.2


Re: [Qemu-devel] [PATCH v2] softfloat: Support float_round_to_odd more places
Posted by Alex Bennée 5 years, 1 month ago
Richard Henderson <richard.henderson@linaro.org> writes:

> Previously this was only supported for roundAndPackFloat64.
>
> New support in round_canonical, round_to_int, float128_round_to_int,
> roundAndPackFloat32, roundAndPackInt32, roundAndPackInt64,
> roundAndPackUint64.  This does not include any of the floatx80 routines,
> as we do not have users for that rounding mode there.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Queued to fpu/next, thanks.

> ---
> v2: Convert float128_round_to_int as well.  Add fp-test support.
> ---
>  fpu/softfloat.c    | 64 ++++++++++++++++++++++++++++++++++++++++++----
>  tests/fp/fp-test.c | 43 ++++++++++++++++++++++++-------
>  2 files changed, 93 insertions(+), 14 deletions(-)
>
> diff --git a/fpu/softfloat.c b/fpu/softfloat.c
> index 9132d7a0b0..76132d4cd5 100644
> --- a/fpu/softfloat.c
> +++ b/fpu/softfloat.c
> @@ -696,6 +696,7 @@ static FloatParts sf_canonicalize(FloatParts part, const FloatFmt *parm,
>  static FloatParts round_canonical(FloatParts p, float_status *s,
>                                    const FloatFmt *parm)
>  {
> +    const uint64_t frac_lsb = parm->frac_lsb;
>      const uint64_t frac_lsbm1 = parm->frac_lsbm1;
>      const uint64_t round_mask = parm->round_mask;
>      const uint64_t roundeven_mask = parm->roundeven_mask;
> @@ -731,6 +732,10 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
>              inc = p.sign ? round_mask : 0;
>              overflow_norm = !p.sign;
>              break;
> +        case float_round_to_odd:
> +            overflow_norm = true;
> +            inc = frac & frac_lsb ? 0 : round_mask;
> +            break;
>          default:
>              g_assert_not_reached();
>          }
> @@ -778,9 +783,14 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
>              shift64RightJamming(frac, 1 - exp, &frac);
>              if (frac & round_mask) {
>                  /* Need to recompute round-to-even.  */
> -                if (s->float_rounding_mode == float_round_nearest_even) {
> +                switch (s->float_rounding_mode) {
> +                case float_round_nearest_even:
>                      inc = ((frac & roundeven_mask) != frac_lsbm1
>                             ? frac_lsbm1 : 0);
> +                    break;
> +                case float_round_to_odd:
> +                    inc = frac & frac_lsb ? 0 : round_mask;
> +                    break;
>                  }
>                  flags |= float_flag_inexact;
>                  frac += inc;
> @@ -1988,6 +1998,9 @@ static FloatParts round_to_int(FloatParts a, int rmode,
>              case float_round_down:
>                  one = a.sign;
>                  break;
> +            case float_round_to_odd:
> +                one = true;
> +                break;
>              default:
>                  g_assert_not_reached();
>              }
> @@ -2021,6 +2034,9 @@ static FloatParts round_to_int(FloatParts a, int rmode,
>              case float_round_down:
>                  inc = a.sign ? rnd_mask : 0;
>                  break;
> +            case float_round_to_odd:
> +                inc = a.frac & frac_lsb ? 0 : rnd_mask;
> +                break;
>              default:
>                  g_assert_not_reached();
>              }
> @@ -3314,6 +3330,9 @@ static int32_t roundAndPackInt32(flag zSign, uint64_t absZ, float_status *status
>      case float_round_down:
>          roundIncrement = zSign ? 0x7f : 0;
>          break;
> +    case float_round_to_odd:
> +        roundIncrement = absZ & 0x80 ? 0 : 0x7f;
> +        break;
>      default:
>          abort();
>      }
> @@ -3368,6 +3387,9 @@ static int64_t roundAndPackInt64(flag zSign, uint64_t absZ0, uint64_t absZ1,
>      case float_round_down:
>          increment = zSign && absZ1;
>          break;
> +    case float_round_to_odd:
> +        increment = !(absZ0 & 1) && absZ1;
> +        break;
>      default:
>          abort();
>      }
> @@ -3424,6 +3446,9 @@ static int64_t roundAndPackUint64(flag zSign, uint64_t absZ0,
>      case float_round_down:
>          increment = zSign && absZ1;
>          break;
> +    case float_round_to_odd:
> +        increment = !(absZ0 & 1) && absZ1;
> +        break;
>      default:
>          abort();
>      }
> @@ -3526,6 +3551,8 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
>      case float_round_down:
>          roundIncrement = zSign ? 0x7f : 0;
>          break;
> +    case float_round_to_odd:
> +        roundIncrement = zSig & 0x80 ? 0 : 0x7f;
>      default:
>          abort();
>          break;
> @@ -3536,8 +3563,10 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
>               || (    ( zExp == 0xFD )
>                    && ( (int32_t) ( zSig + roundIncrement ) < 0 ) )
>             ) {
> +            bool overflow_to_inf = roundingMode != float_round_to_odd &&
> +                                   roundIncrement != 0;
>              float_raise(float_flag_overflow | float_flag_inexact, status);
> -            return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
> +            return packFloat32(zSign, 0xFF, -!overflow_to_inf);
>          }
>          if ( zExp < 0 ) {
>              if (status->flush_to_zero) {
> @@ -3555,6 +3584,13 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
>              if (isTiny && roundBits) {
>                  float_raise(float_flag_underflow, status);
>              }
> +            if (roundingMode == float_round_to_odd) {
> +                /*
> +                 * For round-to-odd case, the roundIncrement depends on
> +                 * zSig which just changed.
> +                 */
> +                roundIncrement = zSig & 0x80 ? 0 : 0x7f;
> +            }
>          }
>      }
>      if (roundBits) {
> @@ -6958,6 +6994,15 @@ float128 float128_round_to_int(float128 a, float_status *status)
>                  add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low);
>              }
>              break;
> +        case float_round_to_odd:
> +            /*
> +             * Note that if lastBitMask == 0, the last bit is the lsb
> +             * of high, and roundBitsMask == -1.
> +             */
> +            if ((lastBitMask ? z.low & lastBitMask : z.high & 1) == 0) {
> +                add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low);
> +            }
> +            break;
>          default:
>              abort();
>          }
> @@ -6969,7 +7014,7 @@ float128 float128_round_to_int(float128 a, float_status *status)
>              status->float_exception_flags |= float_flag_inexact;
>              aSign = extractFloat128Sign( a );
>              switch (status->float_rounding_mode) {
> -             case float_round_nearest_even:
> +            case float_round_nearest_even:
>                  if (    ( aExp == 0x3FFE )
>                       && (   extractFloat128Frac0( a )
>                            | extractFloat128Frac1( a ) )
> @@ -6982,14 +7027,17 @@ float128 float128_round_to_int(float128 a, float_status *status)
>                      return packFloat128(aSign, 0x3FFF, 0, 0);
>                  }
>                  break;
> -             case float_round_down:
> +            case float_round_down:
>                  return
>                        aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
>                      : packFloat128( 0, 0, 0, 0 );
> -             case float_round_up:
> +            case float_round_up:
>                  return
>                        aSign ? packFloat128( 1, 0, 0, 0 )
>                      : packFloat128( 0, 0x3FFF, 0, 0 );
> +
> +            case float_round_to_odd:
> +                return packFloat128(aSign, 0x3FFF, 0, 0);
>              }
>              return packFloat128( aSign, 0, 0, 0 );
>          }
> @@ -7022,6 +7070,12 @@ float128 float128_round_to_int(float128 a, float_status *status)
>                  z.high += roundBitsMask;
>              }
>              break;
> +        case float_round_to_odd:
> +            if ((z.high & lastBitMask) == 0) {
> +                z.high |= (a.low != 0);
> +                z.high += roundBitsMask;
> +            }
> +            break;
>          default:
>              abort();
>          }
> diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
> index 2a35ef601d..471adb862d 100644
> --- a/tests/fp/fp-test.c
> +++ b/tests/fp/fp-test.c
> @@ -125,17 +125,42 @@ static void not_implemented(void)
>
>  static bool blacklisted(unsigned op, int rmode)
>  {
> -    /* odd has only been implemented for a few 128-bit ops */
> +    /* odd has not been implemented for any 80-bit ops */
>      if (rmode == softfloat_round_odd) {
>          switch (op) {
> -        case F128_ADD:
> -        case F128_SUB:
> -        case F128_MUL:
> -        case F128_DIV:
> -        case F128_TO_F64:
> -        case F128_SQRT:
> -            return false;
> -        default:
> +        case EXTF80_TO_UI32:
> +        case EXTF80_TO_UI64:
> +        case EXTF80_TO_I32:
> +        case EXTF80_TO_I64:
> +        case EXTF80_TO_UI32_R_MINMAG:
> +        case EXTF80_TO_UI64_R_MINMAG:
> +        case EXTF80_TO_I32_R_MINMAG:
> +        case EXTF80_TO_I64_R_MINMAG:
> +        case EXTF80_TO_F16:
> +        case EXTF80_TO_F32:
> +        case EXTF80_TO_F64:
> +        case EXTF80_TO_F128:
> +        case EXTF80_ROUNDTOINT:
> +        case EXTF80_ADD:
> +        case EXTF80_SUB:
> +        case EXTF80_MUL:
> +        case EXTF80_DIV:
> +        case EXTF80_REM:
> +        case EXTF80_SQRT:
> +        case EXTF80_EQ:
> +        case EXTF80_LE:
> +        case EXTF80_LT:
> +        case EXTF80_EQ_SIGNALING:
> +        case EXTF80_LE_QUIET:
> +        case EXTF80_LT_QUIET:
> +        case UI32_TO_EXTF80:
> +        case UI64_TO_EXTF80:
> +        case I32_TO_EXTF80:
> +        case I64_TO_EXTF80:
> +        case F16_TO_EXTF80:
> +        case F32_TO_EXTF80:
> +        case F64_TO_EXTF80:
> +        case F128_TO_EXTF80:
>              return true;
>          }
>      }


--
Alex Bennée

Re: [Qemu-devel] [PATCH v2] softfloat: Support float_round_to_odd more places
Posted by David Hildenbrand 5 years, 1 month ago
On 15.02.19 18:02, Richard Henderson wrote:
> Previously this was only supported for roundAndPackFloat64.
> 
> New support in round_canonical, round_to_int, float128_round_to_int,
> roundAndPackFloat32, roundAndPackInt32, roundAndPackInt64,
> roundAndPackUint64.  This does not include any of the floatx80 routines,
> as we do not have users for that rounding mode there.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Thanks, this makes my simple fidbra/fiebra/fixbra test case pass!

So for these parts

Tested-by: David Hildenbrand <david@redhat.com>

Unfortunately I don't have a lot of spare time to do a detailed review
or write more advanced tests for other s390x functions. Maybe once the
vector stuff is in good shape.

Any chance, this along with the other two softfloat patches I sent can
reach master soon? Then Conny can pick up + send my s390x series (after
I resend them based on this patch).

Thanks!

> ---
> v2: Convert float128_round_to_int as well.  Add fp-test support.
> ---
>  fpu/softfloat.c    | 64 ++++++++++++++++++++++++++++++++++++++++++----
>  tests/fp/fp-test.c | 43 ++++++++++++++++++++++++-------
>  2 files changed, 93 insertions(+), 14 deletions(-)
> 
> diff --git a/fpu/softfloat.c b/fpu/softfloat.c
> index 9132d7a0b0..76132d4cd5 100644
> --- a/fpu/softfloat.c
> +++ b/fpu/softfloat.c
> @@ -696,6 +696,7 @@ static FloatParts sf_canonicalize(FloatParts part, const FloatFmt *parm,
>  static FloatParts round_canonical(FloatParts p, float_status *s,
>                                    const FloatFmt *parm)
>  {
> +    const uint64_t frac_lsb = parm->frac_lsb;
>      const uint64_t frac_lsbm1 = parm->frac_lsbm1;
>      const uint64_t round_mask = parm->round_mask;
>      const uint64_t roundeven_mask = parm->roundeven_mask;
> @@ -731,6 +732,10 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
>              inc = p.sign ? round_mask : 0;
>              overflow_norm = !p.sign;
>              break;
> +        case float_round_to_odd:
> +            overflow_norm = true;
> +            inc = frac & frac_lsb ? 0 : round_mask;
> +            break;
>          default:
>              g_assert_not_reached();
>          }
> @@ -778,9 +783,14 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
>              shift64RightJamming(frac, 1 - exp, &frac);
>              if (frac & round_mask) {
>                  /* Need to recompute round-to-even.  */
> -                if (s->float_rounding_mode == float_round_nearest_even) {
> +                switch (s->float_rounding_mode) {
> +                case float_round_nearest_even:
>                      inc = ((frac & roundeven_mask) != frac_lsbm1
>                             ? frac_lsbm1 : 0);
> +                    break;
> +                case float_round_to_odd:
> +                    inc = frac & frac_lsb ? 0 : round_mask;
> +                    break;
>                  }
>                  flags |= float_flag_inexact;
>                  frac += inc;
> @@ -1988,6 +1998,9 @@ static FloatParts round_to_int(FloatParts a, int rmode,
>              case float_round_down:
>                  one = a.sign;
>                  break;
> +            case float_round_to_odd:
> +                one = true;
> +                break;
>              default:
>                  g_assert_not_reached();
>              }
> @@ -2021,6 +2034,9 @@ static FloatParts round_to_int(FloatParts a, int rmode,
>              case float_round_down:
>                  inc = a.sign ? rnd_mask : 0;
>                  break;
> +            case float_round_to_odd:
> +                inc = a.frac & frac_lsb ? 0 : rnd_mask;
> +                break;
>              default:
>                  g_assert_not_reached();
>              }
> @@ -3314,6 +3330,9 @@ static int32_t roundAndPackInt32(flag zSign, uint64_t absZ, float_status *status
>      case float_round_down:
>          roundIncrement = zSign ? 0x7f : 0;
>          break;
> +    case float_round_to_odd:
> +        roundIncrement = absZ & 0x80 ? 0 : 0x7f;
> +        break;
>      default:
>          abort();
>      }
> @@ -3368,6 +3387,9 @@ static int64_t roundAndPackInt64(flag zSign, uint64_t absZ0, uint64_t absZ1,
>      case float_round_down:
>          increment = zSign && absZ1;
>          break;
> +    case float_round_to_odd:
> +        increment = !(absZ0 & 1) && absZ1;
> +        break;
>      default:
>          abort();
>      }
> @@ -3424,6 +3446,9 @@ static int64_t roundAndPackUint64(flag zSign, uint64_t absZ0,
>      case float_round_down:
>          increment = zSign && absZ1;
>          break;
> +    case float_round_to_odd:
> +        increment = !(absZ0 & 1) && absZ1;
> +        break;
>      default:
>          abort();
>      }
> @@ -3526,6 +3551,8 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
>      case float_round_down:
>          roundIncrement = zSign ? 0x7f : 0;
>          break;
> +    case float_round_to_odd:
> +        roundIncrement = zSig & 0x80 ? 0 : 0x7f;
>      default:
>          abort();
>          break;
> @@ -3536,8 +3563,10 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
>               || (    ( zExp == 0xFD )
>                    && ( (int32_t) ( zSig + roundIncrement ) < 0 ) )
>             ) {
> +            bool overflow_to_inf = roundingMode != float_round_to_odd &&
> +                                   roundIncrement != 0;
>              float_raise(float_flag_overflow | float_flag_inexact, status);
> -            return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
> +            return packFloat32(zSign, 0xFF, -!overflow_to_inf);
>          }
>          if ( zExp < 0 ) {
>              if (status->flush_to_zero) {
> @@ -3555,6 +3584,13 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
>              if (isTiny && roundBits) {
>                  float_raise(float_flag_underflow, status);
>              }
> +            if (roundingMode == float_round_to_odd) {
> +                /*
> +                 * For round-to-odd case, the roundIncrement depends on
> +                 * zSig which just changed.
> +                 */
> +                roundIncrement = zSig & 0x80 ? 0 : 0x7f;
> +            }
>          }
>      }
>      if (roundBits) {
> @@ -6958,6 +6994,15 @@ float128 float128_round_to_int(float128 a, float_status *status)
>                  add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low);
>              }
>              break;
> +        case float_round_to_odd:
> +            /*
> +             * Note that if lastBitMask == 0, the last bit is the lsb
> +             * of high, and roundBitsMask == -1.
> +             */
> +            if ((lastBitMask ? z.low & lastBitMask : z.high & 1) == 0) {
> +                add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low);
> +            }
> +            break;
>          default:
>              abort();
>          }
> @@ -6969,7 +7014,7 @@ float128 float128_round_to_int(float128 a, float_status *status)
>              status->float_exception_flags |= float_flag_inexact;
>              aSign = extractFloat128Sign( a );
>              switch (status->float_rounding_mode) {
> -             case float_round_nearest_even:
> +            case float_round_nearest_even:
>                  if (    ( aExp == 0x3FFE )
>                       && (   extractFloat128Frac0( a )
>                            | extractFloat128Frac1( a ) )
> @@ -6982,14 +7027,17 @@ float128 float128_round_to_int(float128 a, float_status *status)
>                      return packFloat128(aSign, 0x3FFF, 0, 0);
>                  }
>                  break;
> -             case float_round_down:
> +            case float_round_down:
>                  return
>                        aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
>                      : packFloat128( 0, 0, 0, 0 );
> -             case float_round_up:
> +            case float_round_up:
>                  return
>                        aSign ? packFloat128( 1, 0, 0, 0 )
>                      : packFloat128( 0, 0x3FFF, 0, 0 );
> +
> +            case float_round_to_odd:
> +                return packFloat128(aSign, 0x3FFF, 0, 0);
>              }
>              return packFloat128( aSign, 0, 0, 0 );
>          }
> @@ -7022,6 +7070,12 @@ float128 float128_round_to_int(float128 a, float_status *status)
>                  z.high += roundBitsMask;
>              }
>              break;
> +        case float_round_to_odd:
> +            if ((z.high & lastBitMask) == 0) {
> +                z.high |= (a.low != 0);
> +                z.high += roundBitsMask;
> +            }
> +            break;
>          default:
>              abort();
>          }
> diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
> index 2a35ef601d..471adb862d 100644
> --- a/tests/fp/fp-test.c
> +++ b/tests/fp/fp-test.c
> @@ -125,17 +125,42 @@ static void not_implemented(void)
>  
>  static bool blacklisted(unsigned op, int rmode)
>  {
> -    /* odd has only been implemented for a few 128-bit ops */
> +    /* odd has not been implemented for any 80-bit ops */
>      if (rmode == softfloat_round_odd) {
>          switch (op) {
> -        case F128_ADD:
> -        case F128_SUB:
> -        case F128_MUL:
> -        case F128_DIV:
> -        case F128_TO_F64:
> -        case F128_SQRT:
> -            return false;
> -        default:
> +        case EXTF80_TO_UI32:
> +        case EXTF80_TO_UI64:
> +        case EXTF80_TO_I32:
> +        case EXTF80_TO_I64:
> +        case EXTF80_TO_UI32_R_MINMAG:
> +        case EXTF80_TO_UI64_R_MINMAG:
> +        case EXTF80_TO_I32_R_MINMAG:
> +        case EXTF80_TO_I64_R_MINMAG:
> +        case EXTF80_TO_F16:
> +        case EXTF80_TO_F32:
> +        case EXTF80_TO_F64:
> +        case EXTF80_TO_F128:
> +        case EXTF80_ROUNDTOINT:
> +        case EXTF80_ADD:
> +        case EXTF80_SUB:
> +        case EXTF80_MUL:
> +        case EXTF80_DIV:
> +        case EXTF80_REM:
> +        case EXTF80_SQRT:
> +        case EXTF80_EQ:
> +        case EXTF80_LE:
> +        case EXTF80_LT:
> +        case EXTF80_EQ_SIGNALING:
> +        case EXTF80_LE_QUIET:
> +        case EXTF80_LT_QUIET:
> +        case UI32_TO_EXTF80:
> +        case UI64_TO_EXTF80:
> +        case I32_TO_EXTF80:
> +        case I64_TO_EXTF80:
> +        case F16_TO_EXTF80:
> +        case F32_TO_EXTF80:
> +        case F64_TO_EXTF80:
> +        case F128_TO_EXTF80:
>              return true;
>          }
>      }
> 


-- 

Thanks,

David / dhildenb