target/arm: Fix bfdotadd_ebf vs nan selection
Implement FPProcessNaNs4 within bfdotadd_ebf, rather than simply letting NaNs propagate through the function. Cc: qemu-stable@nongnu.org Fixes:0e1850182a("target/arm: Implement FPCR.EBF=1 semantics for bfdotadd()") Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20250704142112.1018902-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> (cherry picked from commitbf020eaa67) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
This commit is contained in:
parent
9a98db505f
commit
005184da9d
1 changed files with 53 additions and 22 deletions
|
|
@ -2989,31 +2989,62 @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst)
|
|||
float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2,
|
||||
float_status *fpst, float_status *fpst_odd)
|
||||
{
|
||||
/*
|
||||
* Compare f16_dotadd() in sme_helper.c, but here we have
|
||||
* bfloat16 inputs. In particular that means that we do not
|
||||
* want the FPCR.FZ16 flush semantics, so we use the normal
|
||||
* float_status for the input handling here.
|
||||
*/
|
||||
float64 e1r = float32_to_float64(e1 << 16, fpst);
|
||||
float64 e1c = float32_to_float64(e1 & 0xffff0000u, fpst);
|
||||
float64 e2r = float32_to_float64(e2 << 16, fpst);
|
||||
float64 e2c = float32_to_float64(e2 & 0xffff0000u, fpst);
|
||||
float64 t64;
|
||||
float32 s1r = e1 << 16;
|
||||
float32 s1c = e1 & 0xffff0000u;
|
||||
float32 s2r = e2 << 16;
|
||||
float32 s2c = e2 & 0xffff0000u;
|
||||
float32 t32;
|
||||
|
||||
/*
|
||||
* The ARM pseudocode function FPDot performs both multiplies
|
||||
* and the add with a single rounding operation. Emulate this
|
||||
* by performing the first multiply in round-to-odd, then doing
|
||||
* the second multiply as fused multiply-add, and rounding to
|
||||
* float32 all in one step.
|
||||
*/
|
||||
t64 = float64_mul(e1r, e2r, fpst_odd);
|
||||
t64 = float64r32_muladd(e1c, e2c, t64, 0, fpst);
|
||||
/* C.f. FPProcessNaNs4 */
|
||||
if (float32_is_any_nan(s1r) || float32_is_any_nan(s1c) ||
|
||||
float32_is_any_nan(s2r) || float32_is_any_nan(s2c)) {
|
||||
if (float32_is_signaling_nan(s1r, fpst)) {
|
||||
t32 = s1r;
|
||||
} else if (float32_is_signaling_nan(s1c, fpst)) {
|
||||
t32 = s1c;
|
||||
} else if (float32_is_signaling_nan(s2r, fpst)) {
|
||||
t32 = s2r;
|
||||
} else if (float32_is_signaling_nan(s2c, fpst)) {
|
||||
t32 = s2c;
|
||||
} else if (float32_is_any_nan(s1r)) {
|
||||
t32 = s1r;
|
||||
} else if (float32_is_any_nan(s1c)) {
|
||||
t32 = s1c;
|
||||
} else if (float32_is_any_nan(s2r)) {
|
||||
t32 = s2r;
|
||||
} else {
|
||||
t32 = s2c;
|
||||
}
|
||||
/*
|
||||
* FPConvertNaN(FPProcessNaN(t32)) will be done as part
|
||||
* of the final addition below.
|
||||
*/
|
||||
} else {
|
||||
/*
|
||||
* Compare f16_dotadd() in sme_helper.c, but here we have
|
||||
* bfloat16 inputs. In particular that means that we do not
|
||||
* want the FPCR.FZ16 flush semantics, so we use the normal
|
||||
* float_status for the input handling here.
|
||||
*/
|
||||
float64 e1r = float32_to_float64(s1r, fpst);
|
||||
float64 e1c = float32_to_float64(s1c, fpst);
|
||||
float64 e2r = float32_to_float64(s2r, fpst);
|
||||
float64 e2c = float32_to_float64(s2c, fpst);
|
||||
float64 t64;
|
||||
|
||||
/* This conversion is exact, because we've already rounded. */
|
||||
t32 = float64_to_float32(t64, fpst);
|
||||
/*
|
||||
* The ARM pseudocode function FPDot performs both multiplies
|
||||
* and the add with a single rounding operation. Emulate this
|
||||
* by performing the first multiply in round-to-odd, then doing
|
||||
* the second multiply as fused multiply-add, and rounding to
|
||||
* float32 all in one step.
|
||||
*/
|
||||
t64 = float64_mul(e1r, e2r, fpst_odd);
|
||||
t64 = float64r32_muladd(e1c, e2c, t64, 0, fpst);
|
||||
|
||||
/* This conversion is exact, because we've already rounded. */
|
||||
t32 = float64_to_float32(t64, fpst);
|
||||
}
|
||||
|
||||
/* The final accumulation step is not fused. */
|
||||
return float32_add(sum, t32, fpst);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue