target/arm: Handle FPCR.AH in SVE FTMAD
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, so we can select the correct behaviour. Because the operand is known to be negative, negating the operand is the same as taking the absolute value. Defer this to the muladd operation via flags, so that it happens after NaN detection, which is correct for FPCR.AH. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
6dcd51ccf6
commit
07e6b8d752
@ -5134,16 +5134,24 @@ 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;
|
||||
int flags = 0;
|
||||
|
||||
if (float16_is_neg(mm)) {
|
||||
mm = float16_abs(mm);
|
||||
if (fpcr_ah) {
|
||||
flags = float_muladd_negate_product;
|
||||
} else {
|
||||
mm = float16_abs(mm);
|
||||
}
|
||||
xx += 8;
|
||||
}
|
||||
d[i] = float16_muladd(n[i], mm, coeff[xx], 0, s);
|
||||
d[i] = float16_muladd(n[i], mm, coeff[xx], flags, s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5157,16 +5165,24 @@ 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;
|
||||
int flags = 0;
|
||||
|
||||
if (float32_is_neg(mm)) {
|
||||
mm = float32_abs(mm);
|
||||
if (fpcr_ah) {
|
||||
flags = float_muladd_negate_product;
|
||||
} else {
|
||||
mm = float32_abs(mm);
|
||||
}
|
||||
xx += 8;
|
||||
}
|
||||
d[i] = float32_muladd(n[i], mm, coeff[xx], 0, s);
|
||||
d[i] = float32_muladd(n[i], mm, coeff[xx], flags, s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5184,16 +5200,24 @@ 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;
|
||||
int flags = 0;
|
||||
|
||||
if (float64_is_neg(mm)) {
|
||||
mm = float64_abs(mm);
|
||||
if (fpcr_ah) {
|
||||
flags = float_muladd_negate_product;
|
||||
} else {
|
||||
mm = float64_abs(mm);
|
||||
}
|
||||
xx += 8;
|
||||
}
|
||||
d[i] = float64_muladd(n[i], mm, coeff[xx], 0, s);
|
||||
d[i] = float64_muladd(n[i], mm, coeff[xx], flags, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3685,7 +3685,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_A64_F16 : FPST_A64)
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user