The negation step in the SVE FTMAD insn mustn't negate a NaN when FPCR.AH is set. Pass FPCR.AH to the helper via the SIMD data field and use that to determine whether to do the negation.
Signed-off-by: Peter Maydell <peter.mayd...@linaro.org> --- target/arm/tcg/sve_helper.c | 21 +++++++++++++++------ target/arm/tcg/translate-sve.c | 3 ++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index a39a3ed0cf9..3f38e078291 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c @@ -5143,13 +5143,16 @@ void HELPER(sve_ftmad_h)(void *vd, void *vn, void *vm, 0x3c00, 0xb800, 0x293a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; intptr_t i, opr_sz = simd_oprsz(desc) / sizeof(float16); - intptr_t x = simd_data(desc); + intptr_t x = extract32(desc, SIMD_DATA_SHIFT, 3); + bool fpcr_ah = extract32(desc, SIMD_DATA_SHIFT + 3, 1); float16 *d = vd, *n = vn, *m = vm; for (i = 0; i < opr_sz; i++) { float16 mm = m[i]; intptr_t xx = x; if (float16_is_neg(mm)) { - mm = float16_abs(mm); + if (!(fpcr_ah && float16_is_any_nan(mm))) { + mm = float16_abs(mm); + } xx += 8; } d[i] = float16_muladd(n[i], mm, coeff[xx], 0, s); @@ -5166,13 +5169,16 @@ void HELPER(sve_ftmad_s)(void *vd, void *vn, void *vm, 0x37cd37cc, 0x00000000, 0x00000000, 0x00000000, }; intptr_t i, opr_sz = simd_oprsz(desc) / sizeof(float32); - intptr_t x = simd_data(desc); + intptr_t x = extract32(desc, SIMD_DATA_SHIFT, 3); + bool fpcr_ah = extract32(desc, SIMD_DATA_SHIFT + 3, 1); float32 *d = vd, *n = vn, *m = vm; for (i = 0; i < opr_sz; i++) { float32 mm = m[i]; intptr_t xx = x; if (float32_is_neg(mm)) { - mm = float32_abs(mm); + if (!(fpcr_ah && float32_is_any_nan(mm))) { + mm = float32_abs(mm); + } xx += 8; } d[i] = float32_muladd(n[i], mm, coeff[xx], 0, s); @@ -5193,13 +5199,16 @@ void HELPER(sve_ftmad_d)(void *vd, void *vn, void *vm, 0x3e21ee96d2641b13ull, 0xbda8f76380fbb401ull, }; intptr_t i, opr_sz = simd_oprsz(desc) / sizeof(float64); - intptr_t x = simd_data(desc); + intptr_t x = extract32(desc, SIMD_DATA_SHIFT, 3); + bool fpcr_ah = extract32(desc, SIMD_DATA_SHIFT + 3, 1); float64 *d = vd, *n = vn, *m = vm; for (i = 0; i < opr_sz; i++) { float64 mm = m[i]; intptr_t xx = x; if (float64_is_neg(mm)) { - mm = float64_abs(mm); + if (!(fpcr_ah && float64_is_any_nan(mm))) { + mm = float64_abs(mm); + } xx += 8; } d[i] = float64_muladd(n[i], mm, coeff[xx], 0, s); diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index 2d70b0faad2..26bdda8f96e 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -3682,7 +3682,8 @@ static gen_helper_gvec_3_ptr * const ftmad_fns[4] = { gen_helper_sve_ftmad_s, gen_helper_sve_ftmad_d, }; TRANS_FEAT_NONSTREAMING(FTMAD, aa64_sve, gen_gvec_fpst_zzz, - ftmad_fns[a->esz], a->rd, a->rn, a->rm, a->imm, + ftmad_fns[a->esz], a->rd, a->rn, a->rm, + a->imm | (s->fpcr_ah << 3), a->esz == MO_16 ? FPST_FPCR_F16_A64 : FPST_FPCR_A64) /* -- 2.34.1