softfloat: add APIs to handle alternative sNaN propagation for fmax/fmin

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>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20211021160847.2748577-2-frank.chang@sifive.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Chih-Min Chao 2021-10-22 00:08:45 +08:00 committed by Alistair Francis
parent 50d1608764
commit 0e9030376e
3 changed files with 46 additions and 8 deletions

View File

@ -1219,14 +1219,35 @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b,
if (unlikely(ab_mask & float_cmask_anynan)) {
/*
* For minnum/maxnum, if one operand is a QNaN, and the other
* For minNum/maxNum (IEEE 754-2008)
* or minimumNumber/maximumNumber (IEEE 754-2019),
* if one operand is a QNaN, and the other
* operand is numerical, then return numerical argument.
*/
if ((flags & minmax_isnum)
if ((flags & (minmax_isnum | minmax_isnumber))
&& !(ab_mask & float_cmask_snan)
&& (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_isnumber)
&& (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);
}

View File

@ -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() and maximumNumber()
* operations.
*/
minmax_isnumber = 8,
};
/* Simple helpers for checking if, or what kind of, NaN we have */
@ -3927,12 +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, minnummag, minmax_ismin | minmax_isnum | minmax_ismag)
MINMAX_1(type, max, 0) \
MINMAX_1(type, maxnum, minmax_isnum) \
MINMAX_1(type, maxnummag, minmax_isnum | minmax_ismag) \
MINMAX_1(type, maximum_number, minmax_isnumber) \
MINMAX_1(type, min, minmax_ismin) \
MINMAX_1(type, minnum, minmax_ismin | minmax_isnum) \
MINMAX_1(type, minnummag, minmax_ismin | minmax_isnum | minmax_ismag) \
MINMAX_1(type, minimum_number, minmax_ismin | minmax_isnumber) \
MINMAX_2(float16)
MINMAX_2(bfloat16)

View File

@ -243,6 +243,8 @@ float16 float16_minnum(float16, float16, float_status *status);
float16 float16_maxnum(float16, float16, float_status *status);
float16 float16_minnummag(float16, float16, float_status *status);
float16 float16_maxnummag(float16, float16, float_status *status);
float16 float16_minimum_number(float16, float16, float_status *status);
float16 float16_maximum_number(float16, float16, float_status *status);
float16 float16_sqrt(float16, float_status *status);
FloatRelation float16_compare(float16, float16, float_status *status);
FloatRelation float16_compare_quiet(float16, float16, float_status *status);
@ -422,6 +424,8 @@ bfloat16 bfloat16_minnum(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_maxnum(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_minnummag(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_maxnummag(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_minimum_number(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_maximum_number(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_sqrt(bfloat16, float_status *status);
FloatRelation bfloat16_compare(bfloat16, bfloat16, float_status *status);
FloatRelation bfloat16_compare_quiet(bfloat16, bfloat16, float_status *status);
@ -589,6 +593,8 @@ float32 float32_minnum(float32, float32, float_status *status);
float32 float32_maxnum(float32, float32, float_status *status);
float32 float32_minnummag(float32, float32, float_status *status);
float32 float32_maxnummag(float32, float32, float_status *status);
float32 float32_minimum_number(float32, float32, float_status *status);
float32 float32_maximum_number(float32, float32, float_status *status);
bool float32_is_quiet_nan(float32, float_status *status);
bool float32_is_signaling_nan(float32, float_status *status);
float32 float32_silence_nan(float32, float_status *status);
@ -778,6 +784,8 @@ float64 float64_minnum(float64, float64, float_status *status);
float64 float64_maxnum(float64, float64, float_status *status);
float64 float64_minnummag(float64, float64, float_status *status);
float64 float64_maxnummag(float64, float64, float_status *status);
float64 float64_minimum_number(float64, float64, float_status *status);
float64 float64_maximum_number(float64, float64, float_status *status);
bool float64_is_quiet_nan(float64 a, float_status *status);
bool float64_is_signaling_nan(float64, float_status *status);
float64 float64_silence_nan(float64, float_status *status);
@ -1210,6 +1218,8 @@ float128 float128_minnum(float128, float128, float_status *status);
float128 float128_maxnum(float128, float128, float_status *status);
float128 float128_minnummag(float128, float128, float_status *status);
float128 float128_maxnummag(float128, float128, float_status *status);
float128 float128_minimum_number(float128, float128, float_status *status);
float128 float128_maximum_number(float128, float128, float_status *status);
bool float128_is_quiet_nan(float128, float_status *status);
bool float128_is_signaling_nan(float128, float_status *status);
float128 float128_silence_nan(float128, float_status *status);