mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 12:23:53 -06:00
fpu: handle raising Invalid for infzero in pick_nan_muladd
For IEEE fused multiply-add, the (0 * inf) + NaN case should raise Invalid for the multiplication of 0 by infinity. Currently we handle this in the per-architecture ifdef ladder in pickNaNMulAdd(). However, since this isn't really architecture specific we can hoist it up to the generic code. For the cases where the infzero test in pickNaNMulAdd was returning 2, we can delete the check entirely and allow the code to fall into the normal pick-a-NaN handling, because this will return 2 anyway (input 'c' being the only NaN in this case). For the cases where infzero was returning 3 to indicate "return the default NaN", we must retain that "return 3". For Arm, this looks like it might be a behaviour change because we used to set float_flag_invalid | float_flag_invalid_imz only if C is a quiet NaN. However, it is not, because Arm target code never looks at float_flag_invalid_imz, and for the (0 * inf) + SNaN case we already raised float_flag_invalid via the "abc_mask & float_cmask_snan" check in pick_nan_muladd. For any target architecture using the "default implementation" at the bottom of the ifdef, this is a behaviour change but will be fixing a bug (where we failed to raise the Invalid exception for (0 * inf + QNaN). The architectures using the default case are: * hppa * i386 * sh4 * tricore The x86, Tricore and SH4 CPU architecture manuals are clear that this should have raised Invalid; HPPA is a bit vaguer but still seems clear enough. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20241202131347.498124-2-peter.maydell@linaro.org
This commit is contained in:
parent
973a2fac48
commit
8adcff4ae7
2 changed files with 8 additions and 34 deletions
|
@ -66,19 +66,20 @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
|
||||||
int ab_mask, int abc_mask)
|
int ab_mask, int abc_mask)
|
||||||
{
|
{
|
||||||
int which;
|
int which;
|
||||||
|
bool infzero = (ab_mask == float_cmask_infzero);
|
||||||
|
|
||||||
if (unlikely(abc_mask & float_cmask_snan)) {
|
if (unlikely(abc_mask & float_cmask_snan)) {
|
||||||
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
|
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
which = pickNaNMulAdd(a->cls, b->cls, c->cls,
|
if (infzero) {
|
||||||
ab_mask == float_cmask_infzero, s);
|
/* This is (0 * inf) + NaN or (inf * 0) + NaN */
|
||||||
|
float_raise(float_flag_invalid | float_flag_invalid_imz, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s);
|
||||||
|
|
||||||
if (s->default_nan_mode || which == 3) {
|
if (s->default_nan_mode || which == 3) {
|
||||||
/*
|
|
||||||
* Note that this check is after pickNaNMulAdd so that function
|
|
||||||
* has an opportunity to set the Invalid flag for infzero.
|
|
||||||
*/
|
|
||||||
parts_default_nan(a, s);
|
parts_default_nan(a, s);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
|
@ -480,7 +480,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||||
* the default NaN
|
* the default NaN
|
||||||
*/
|
*/
|
||||||
if (infzero && is_qnan(c_cls)) {
|
if (infzero && is_qnan(c_cls)) {
|
||||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,7 +506,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||||
* case sets InvalidOp and returns the default NaN
|
* case sets InvalidOp and returns the default NaN
|
||||||
*/
|
*/
|
||||||
if (infzero) {
|
if (infzero) {
|
||||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
/* Prefer sNaN over qNaN, in the a, b, c order. */
|
/* Prefer sNaN over qNaN, in the a, b, c order. */
|
||||||
|
@ -529,10 +527,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||||
* For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
|
* For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
|
||||||
* case sets InvalidOp and returns the input value 'c'
|
* case sets InvalidOp and returns the input value 'c'
|
||||||
*/
|
*/
|
||||||
if (infzero) {
|
|
||||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
/* Prefer sNaN over qNaN, in the c, a, b order. */
|
/* Prefer sNaN over qNaN, in the c, a, b order. */
|
||||||
if (is_snan(c_cls)) {
|
if (is_snan(c_cls)) {
|
||||||
return 2;
|
return 2;
|
||||||
|
@ -553,10 +547,7 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||||
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
|
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
|
||||||
* case sets InvalidOp and returns the input value 'c'
|
* case sets InvalidOp and returns the input value 'c'
|
||||||
*/
|
*/
|
||||||
if (infzero) {
|
|
||||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
/* Prefer sNaN over qNaN, in the c, a, b order. */
|
/* Prefer sNaN over qNaN, in the c, a, b order. */
|
||||||
if (is_snan(c_cls)) {
|
if (is_snan(c_cls)) {
|
||||||
return 2;
|
return 2;
|
||||||
|
@ -576,10 +567,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||||
* to return an input NaN if we have one (ie c) rather than generating
|
* to return an input NaN if we have one (ie c) rather than generating
|
||||||
* a default NaN
|
* a default NaN
|
||||||
*/
|
*/
|
||||||
if (infzero) {
|
|
||||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
|
/* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
|
||||||
* otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
|
* otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
|
||||||
|
@ -592,14 +579,9 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#elif defined(TARGET_RISCV)
|
#elif defined(TARGET_RISCV)
|
||||||
/* For RISC-V, InvalidOp is set when multiplicands are Inf and zero */
|
|
||||||
if (infzero) {
|
|
||||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
|
||||||
}
|
|
||||||
return 3; /* default NaN */
|
return 3; /* default NaN */
|
||||||
#elif defined(TARGET_S390X)
|
#elif defined(TARGET_S390X)
|
||||||
if (infzero) {
|
if (infzero) {
|
||||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -617,11 +599,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
/* For (inf,0,nan) return c. */
|
|
||||||
if (infzero) {
|
|
||||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
/* Prefer SNaN over QNaN, order C, B, A. */
|
/* Prefer SNaN over QNaN, order C, B, A. */
|
||||||
if (is_snan(c_cls)) {
|
if (is_snan(c_cls)) {
|
||||||
return 2;
|
return 2;
|
||||||
|
@ -641,10 +618,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||||
* For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns
|
* For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns
|
||||||
* an input NaN if we have one (ie c).
|
* an input NaN if we have one (ie c).
|
||||||
*/
|
*/
|
||||||
if (infzero) {
|
|
||||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (status->use_first_nan) {
|
if (status->use_first_nan) {
|
||||||
if (is_nan(a_cls)) {
|
if (is_nan(a_cls)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue