target/arm: Handle FPCR.NEP for FCVTXN (scalar)

Unlike the other users of do_2misc_narrow_scalar(), FCVTXN (scalar)
is always double-to-single and must honour FPCR.NEP.  Implement this
directly in a trans function rather than using
do_2misc_narrow_scalar().

We still need gen_fcvtxn_sd() and the f_scalar_fcvtxn[] array for
the FCVTXN (vector) insn, so we move those down in the file to
where they are used.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Peter Maydell 2025-02-01 16:39:25 +00:00
parent 64339259a9
commit 555639065d

View File

@ -9247,24 +9247,21 @@ static ArithOneOp * const f_scalar_uqxtn[] = {
};
TRANS(UQXTN_s, do_2misc_narrow_scalar, a, f_scalar_uqxtn)
static void gen_fcvtxn_sd(TCGv_i64 d, TCGv_i64 n)
static bool trans_FCVTXN_s(DisasContext *s, arg_rr_e *a)
{
/*
* 64 bit to 32 bit float conversion
* with von Neumann rounding (round to odd)
*/
TCGv_i32 tmp = tcg_temp_new_i32();
gen_helper_fcvtx_f64_to_f32(tmp, n, fpstatus_ptr(FPST_A64));
tcg_gen_extu_i32_i64(d, tmp);
if (fp_access_check(s)) {
/*
* 64 bit to 32 bit float conversion
* with von Neumann rounding (round to odd)
*/
TCGv_i64 src = read_fp_dreg(s, a->rn);
TCGv_i32 dst = tcg_temp_new_i32();
gen_helper_fcvtx_f64_to_f32(dst, src, fpstatus_ptr(FPST_A64));
write_fp_sreg_merging(s, a->rd, a->rd, dst);
}
return true;
}
static ArithOneOp * const f_scalar_fcvtxn[] = {
NULL,
NULL,
gen_fcvtxn_sd,
};
TRANS(FCVTXN_s, do_2misc_narrow_scalar, a, f_scalar_fcvtxn)
#undef WRAP_ENV
static bool do_gvec_fn2(DisasContext *s, arg_qrr_e *a, GVecGen2Fn *fn)
@ -9366,11 +9363,27 @@ static void gen_fcvtn_sd(TCGv_i64 d, TCGv_i64 n)
tcg_gen_extu_i32_i64(d, tmp);
}
static void gen_fcvtxn_sd(TCGv_i64 d, TCGv_i64 n)
{
/*
* 64 bit to 32 bit float conversion
* with von Neumann rounding (round to odd)
*/
TCGv_i32 tmp = tcg_temp_new_i32();
gen_helper_fcvtx_f64_to_f32(tmp, n, fpstatus_ptr(FPST_A64));
tcg_gen_extu_i32_i64(d, tmp);
}
static ArithOneOp * const f_vector_fcvtn[] = {
NULL,
gen_fcvtn_hs,
gen_fcvtn_sd,
};
static ArithOneOp * const f_scalar_fcvtxn[] = {
NULL,
NULL,
gen_fcvtxn_sd,
};
TRANS(FCVTN_v, do_2misc_narrow_vector, a, f_vector_fcvtn)
TRANS(FCVTXN_v, do_2misc_narrow_vector, a, f_scalar_fcvtxn)