Message ID | 20211015061138.3766862-1-frank.chang@sifive.com |
---|---|
State | New |
Headers | show |
Series | [v3,1/2] softfloat: add APIs to handle alternative sNaN propagation for fmax/fmin | expand |
On Fri, Oct 15, 2021 at 2:11 PM <frank.chang@sifive.com> wrote: > From: Chih-Min Chao <chihmin.chao@sifive.com> > > For "fmax/fmin ft0, ft1, ft2" and if one of the inputs is sNaN, > > The original logic: > Return NaN and set invalid flag if ft1 == sNaN || ft2 == sNan. > > The alternative path: > Set invalid flag if ft1 == sNaN || ft2 == sNaN. > Return NaN only if ft1 == NaN && ft2 == NaN. > > The IEEE 754 spec allows both implementation and some architecture such > as riscv choose different defintions in two spec versions. > (riscv-spec-v2.2 use original version, riscv-spec-20191213 changes to > alternative) > > Signed-off-by: Chih-Min Chao <chihmin.chao@sifive.com> > Signed-off-by: Frank Chang <frank.chang@sifive.com> > --- > fpu/softfloat-parts.c.inc | 19 +++++++++++++++++++ > fpu/softfloat.c | 18 +++++++++++++----- > include/fpu/softfloat.h | 10 ++++++++++ > 3 files changed, 42 insertions(+), 5 deletions(-) > > diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc > index dddee92d6ee..a8d74624f5a 100644 > --- a/fpu/softfloat-parts.c.inc > +++ b/fpu/softfloat-parts.c.inc > @@ -1227,6 +1227,25 @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, > FloatPartsN *b, > && (ab_mask & ~float_cmask_qnan)) { > return is_nan(a->cls) ? b : a; > } > + > + /* > + * In IEEE 754-2019, minNum, maxNum, minNumMag and maxNumMag > + * are removed and replaced with minimum, minimumNumber, maximum > + * and maximumNumber. > + * minimumNumber/maximumNumber behavior for SNaN is changed to: > + * If both operands are NaNs, a QNaN is returned. > + * If either operand is a SNaN, > + * an invalid operation exception is signaled, > + * but unless both operands are NaNs, > + * the SNaN is otherwise ignored and not converted to a QNaN. > + */ > + if (!(~flags & (minmax_isnum | minmax_snan_noprop)) > + && (ab_mask & float_cmask_snan) > + && (ab_mask & ~float_cmask_anynan)) { > + float_raise(float_flag_invalid, s); > + return is_nan(a->cls) ? b : a; > + } > + > return parts_pick_nan(a, b, s); > } > > diff --git a/fpu/softfloat.c b/fpu/softfloat.c > index 6e769f990c2..eee65e9934c 100644 > --- a/fpu/softfloat.c > +++ b/fpu/softfloat.c > @@ -436,6 +436,11 @@ enum { > minmax_isnum = 2, > /* Set for the IEEE 754-2008 minNumMag() and minNumMag() operations. > */ > minmax_ismag = 4, > + /* > + * Set for the IEEE 754-2019 minimumNumber() maximumNumber() > operations, > + * without sNaN propagation. > + */ > + minmax_snan_noprop = 8, > }; > > /* Simple helpers for checking if, or what kind of, NaN we have */ > @@ -3927,11 +3932,14 @@ static float128 float128_minmax(float128 a, > float128 b, > { return type##_minmax(a, b, s, flags); } > > #define MINMAX_2(type) \ > - MINMAX_1(type, max, 0) \ > - MINMAX_1(type, maxnum, minmax_isnum) \ > - MINMAX_1(type, maxnummag, minmax_isnum | minmax_ismag) \ > - MINMAX_1(type, min, minmax_ismin) \ > - MINMAX_1(type, minnum, minmax_ismin | minmax_isnum) \ > + MINMAX_1(type, max, 0) \ > + MINMAX_1(type, maxnum, minmax_isnum) \ > + MINMAX_1(type, maxnum_noprop, minmax_isnum | minmax_snan_noprop) \ > + MINMAX_1(type, maxnummag, minmax_isnum | minmax_ismag) \ > + MINMAX_1(type, min, minmax_ismin) \ > + MINMAX_1(type, minnum, minmax_ismin | minmax_isnum) \ > + MINMAX_1(type, minnum_noprop, minmax_ismin | minmax_isnum | \ > + minmax_snan_noprop) \ > MINMAX_1(type, minnummag, minmax_ismin | minmax_isnum | minmax_ismag) > > MINMAX_2(float16) > diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h > index ec7dca09606..b77917ea661 100644 > --- a/include/fpu/softfloat.h > +++ b/include/fpu/softfloat.h > @@ -241,6 +241,8 @@ float16 float16_min(float16, float16, float_status > *status); > float16 float16_max(float16, float16, float_status *status); > float16 float16_minnum(float16, float16, float_status *status); > float16 float16_maxnum(float16, float16, float_status *status); > +float16 float16_minnum_noprop(float16, float16, float_status *status); > +float16 float16_maxnum_noprop(float16, float16, float_status *status); > float16 float16_minnummag(float16, float16, float_status *status); > float16 float16_maxnummag(float16, float16, float_status *status); > float16 float16_sqrt(float16, float_status *status); > @@ -420,6 +422,8 @@ bfloat16 bfloat16_min(bfloat16, bfloat16, float_status > *status); > bfloat16 bfloat16_max(bfloat16, bfloat16, float_status *status); > bfloat16 bfloat16_minnum(bfloat16, bfloat16, float_status *status); > bfloat16 bfloat16_maxnum(bfloat16, bfloat16, float_status *status); > +bfloat16 bfloat16_minnum_noprop(bfloat16, bfloat16, float_status *status); > +bfloat16 bfloat16_maxnum_noprop(bfloat16, bfloat16, float_status *status); > bfloat16 bfloat16_minnummag(bfloat16, bfloat16, float_status *status); > bfloat16 bfloat16_maxnummag(bfloat16, bfloat16, float_status *status); > bfloat16 bfloat16_sqrt(bfloat16, float_status *status); > @@ -587,6 +591,8 @@ float32 float32_min(float32, float32, float_status > *status); > float32 float32_max(float32, float32, float_status *status); > float32 float32_minnum(float32, float32, float_status *status); > float32 float32_maxnum(float32, float32, float_status *status); > +float32 float32_minnum_noprop(float32, float32, float_status *status); > +float32 float32_maxnum_noprop(float32, float32, float_status *status); > float32 float32_minnummag(float32, float32, float_status *status); > float32 float32_maxnummag(float32, float32, float_status *status); > bool float32_is_quiet_nan(float32, float_status *status); > @@ -776,6 +782,8 @@ float64 float64_min(float64, float64, float_status > *status); > float64 float64_max(float64, float64, float_status *status); > float64 float64_minnum(float64, float64, float_status *status); > float64 float64_maxnum(float64, float64, float_status *status); > +float64 float64_minnum_noprop(float64, float64, float_status *status); > +float64 float64_maxnum_noprop(float64, float64, float_status *status); > float64 float64_minnummag(float64, float64, float_status *status); > float64 float64_maxnummag(float64, float64, float_status *status); > bool float64_is_quiet_nan(float64 a, float_status *status); > @@ -1208,6 +1216,8 @@ float128 float128_min(float128, float128, > float_status *status); > float128 float128_max(float128, float128, float_status *status); > float128 float128_minnum(float128, float128, float_status *status); > float128 float128_maxnum(float128, float128, float_status *status); > +float128 float128_minnum_noprop(float128, float128, float_status *status); > +float128 float128_maxnum_noprop(float128, float128, float_status *status); > float128 float128_minnummag(float128, float128, float_status *status); > float128 float128_maxnummag(float128, float128, float_status *status); > bool float128_is_quiet_nan(float128, float_status *status); > -- > 2.25.1 > > I should add the cover letter for this series of patchset, will resend it. Sorry for the confusion. Regards, Frank Chang
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index dddee92d6ee..a8d74624f5a 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -1227,6 +1227,25 @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b, && (ab_mask & ~float_cmask_qnan)) { return is_nan(a->cls) ? b : a; } + + /* + * In IEEE 754-2019, minNum, maxNum, minNumMag and maxNumMag + * are removed and replaced with minimum, minimumNumber, maximum + * and maximumNumber. + * minimumNumber/maximumNumber behavior for SNaN is changed to: + * If both operands are NaNs, a QNaN is returned. + * If either operand is a SNaN, + * an invalid operation exception is signaled, + * but unless both operands are NaNs, + * the SNaN is otherwise ignored and not converted to a QNaN. + */ + if (!(~flags & (minmax_isnum | minmax_snan_noprop)) + && (ab_mask & float_cmask_snan) + && (ab_mask & ~float_cmask_anynan)) { + float_raise(float_flag_invalid, s); + return is_nan(a->cls) ? b : a; + } + return parts_pick_nan(a, b, s); } diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 6e769f990c2..eee65e9934c 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -436,6 +436,11 @@ enum { minmax_isnum = 2, /* Set for the IEEE 754-2008 minNumMag() and minNumMag() operations. */ minmax_ismag = 4, + /* + * Set for the IEEE 754-2019 minimumNumber() maximumNumber() operations, + * without sNaN propagation. + */ + minmax_snan_noprop = 8, }; /* Simple helpers for checking if, or what kind of, NaN we have */ @@ -3927,11 +3932,14 @@ static float128 float128_minmax(float128 a, float128 b, { return type##_minmax(a, b, s, flags); } #define MINMAX_2(type) \ - MINMAX_1(type, max, 0) \ - MINMAX_1(type, maxnum, minmax_isnum) \ - MINMAX_1(type, maxnummag, minmax_isnum | minmax_ismag) \ - MINMAX_1(type, min, minmax_ismin) \ - MINMAX_1(type, minnum, minmax_ismin | minmax_isnum) \ + MINMAX_1(type, max, 0) \ + MINMAX_1(type, maxnum, minmax_isnum) \ + MINMAX_1(type, maxnum_noprop, minmax_isnum | minmax_snan_noprop) \ + MINMAX_1(type, maxnummag, minmax_isnum | minmax_ismag) \ + MINMAX_1(type, min, minmax_ismin) \ + MINMAX_1(type, minnum, minmax_ismin | minmax_isnum) \ + MINMAX_1(type, minnum_noprop, minmax_ismin | minmax_isnum | \ + minmax_snan_noprop) \ MINMAX_1(type, minnummag, minmax_ismin | minmax_isnum | minmax_ismag) MINMAX_2(float16) diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index ec7dca09606..b77917ea661 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -241,6 +241,8 @@ float16 float16_min(float16, float16, float_status *status); float16 float16_max(float16, float16, float_status *status); float16 float16_minnum(float16, float16, float_status *status); float16 float16_maxnum(float16, float16, float_status *status); +float16 float16_minnum_noprop(float16, float16, float_status *status); +float16 float16_maxnum_noprop(float16, float16, float_status *status); float16 float16_minnummag(float16, float16, float_status *status); float16 float16_maxnummag(float16, float16, float_status *status); float16 float16_sqrt(float16, float_status *status); @@ -420,6 +422,8 @@ bfloat16 bfloat16_min(bfloat16, bfloat16, float_status *status); bfloat16 bfloat16_max(bfloat16, bfloat16, float_status *status); bfloat16 bfloat16_minnum(bfloat16, bfloat16, float_status *status); bfloat16 bfloat16_maxnum(bfloat16, bfloat16, float_status *status); +bfloat16 bfloat16_minnum_noprop(bfloat16, bfloat16, float_status *status); +bfloat16 bfloat16_maxnum_noprop(bfloat16, bfloat16, float_status *status); bfloat16 bfloat16_minnummag(bfloat16, bfloat16, float_status *status); bfloat16 bfloat16_maxnummag(bfloat16, bfloat16, float_status *status); bfloat16 bfloat16_sqrt(bfloat16, float_status *status); @@ -587,6 +591,8 @@ float32 float32_min(float32, float32, float_status *status); float32 float32_max(float32, float32, float_status *status); float32 float32_minnum(float32, float32, float_status *status); float32 float32_maxnum(float32, float32, float_status *status); +float32 float32_minnum_noprop(float32, float32, float_status *status); +float32 float32_maxnum_noprop(float32, float32, float_status *status); float32 float32_minnummag(float32, float32, float_status *status); float32 float32_maxnummag(float32, float32, float_status *status); bool float32_is_quiet_nan(float32, float_status *status); @@ -776,6 +782,8 @@ float64 float64_min(float64, float64, float_status *status); float64 float64_max(float64, float64, float_status *status); float64 float64_minnum(float64, float64, float_status *status); float64 float64_maxnum(float64, float64, float_status *status); +float64 float64_minnum_noprop(float64, float64, float_status *status); +float64 float64_maxnum_noprop(float64, float64, float_status *status); float64 float64_minnummag(float64, float64, float_status *status); float64 float64_maxnummag(float64, float64, float_status *status); bool float64_is_quiet_nan(float64 a, float_status *status); @@ -1208,6 +1216,8 @@ float128 float128_min(float128, float128, float_status *status); float128 float128_max(float128, float128, float_status *status); float128 float128_minnum(float128, float128, float_status *status); float128 float128_maxnum(float128, float128, float_status *status); +float128 float128_minnum_noprop(float128, float128, float_status *status); +float128 float128_maxnum_noprop(float128, float128, float_status *status); float128 float128_minnummag(float128, float128, float_status *status); float128 float128_maxnummag(float128, float128, float_status *status); bool float128_is_quiet_nan(float128, float_status *status);