target/arm: Implement FCVTN (16- to 8-bit fp) for AdvSIMD
Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Richard Henderson committed
Jun 9, 2026 at 12:20 UTC
da6726754193221c5f57ec368c3dc5e35617b953
4 files changed
+56
target/arm/tcg/a64.decode
+2
@@ -1212,6 +1212,8 @@ FAMIN 0.10 1110 1.1 ..... 11011 1 ..... ..... @qrrr_sd
1212
FSCALE 0.10 1110 110 ..... 00111 1 ..... ..... @qrrr_h
1213
FSCALE 0.10 1110 1.1 ..... 11111 1 ..... ..... @qrrr_sd
1214
1215
+FCVTN_bh 0.00 1110 010 ..... 11110 1 ..... ..... @qrrr_h
1216
+
1217
### Advanced SIMD scalar x indexed element
1218
1219
FMUL_si 0101 1111 00 .. .... 1001 . 0 ..... ..... @rrx_h
target/arm/tcg/fp8_helper.c
+37
@@ -180,6 +180,13 @@ static uint8_t fcvt_b16_to_fp8(bfloat16 x, fcvt_fp8_output_fn *f8fmt,
180
return f8fmt(&p, scale, saturate, s);
181
}
182
183
+static uint8_t fcvt_f16_to_fp8(float16 x, fcvt_fp8_output_fn *f8fmt,
184
+ int scale, bool saturate, float_status *s)
185
+{
186
+ FloatParts64 p = float16_unpack_canonical(x, s);
187
+ return f8fmt(&p, scale, saturate, s);
188
+}
189
+
190
void HELPER(advsimd_bfcvtl)(void *vd, void *vn, CPUARMState *env, uint32_t desc)
191
{
192
FP8Context ctx = fp8_src_start(env, desc, 0x3f);
@@ -369,3 +376,33 @@ void HELPER(sve2_bfcvtn_bh)(void *vd, void *vn, CPUARMState *env, uint32_t desc)
376
377
fp8_cvt_finish(env, &ctx);
378
}
379
+
380
+void HELPER(gvec_fcvt_bh)(void *vd, void *vn, void *vm,
381
+ CPUARMState *env, uint32_t desc)
382
+{
383
+ FP8Context ctx = fp8_dst_start(env, desc, true);
384
+ fcvt_fp8_output_fn *output_fmt = fcvt_fp8_output_fmt[ctx.f8fmt];
385
+ uint16_t *n = vn;
386
+ uint16_t *m = vm;
387
+ uint8_t *d = vd;
388
+ bool osc = FIELD_EX64(env->vfp.fpmr, FPMR, OSC);
389
+ size_t oprsz = simd_oprsz(desc);
390
+ size_t nelem = oprsz / 2;
391
+ ARMVectorReg scratch;
392
+
393
+ if (vd == vm) {
394
+ m = memcpy(&scratch, vm, oprsz);
395
+ }
396
+
397
+ for (size_t i = 0; i < nelem; ++i) {
398
+ d[H1(i)] = fcvt_f16_to_fp8(n[H2(i)], output_fmt,
399
+ ctx.scale, osc, &ctx.stat);
400
+ }
401
+ for (size_t i = 0; i < nelem; ++i) {
402
+ d[H1(i) + nelem] = fcvt_f16_to_fp8(m[H2(i)], output_fmt,
403
+ ctx.scale, osc, &ctx.stat);
404
+ }
405
+
406
+ fp8_cvt_finish(env, &ctx);
407
+ clear_tail(vd, oprsz, simd_maxsz(desc));
408
+}
target/arm/tcg/helper-fp8-defs.h
+2
@@ -14,3 +14,5 @@ DEF_HELPER_FLAGS_4(sme2_fcvt_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
14
DEF_HELPER_FLAGS_4(sme2_fcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
15
16
DEF_HELPER_FLAGS_4(sve2_bfcvtn_bh, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
17
+
18
+DEF_HELPER_FLAGS_5(gvec_fcvt_bh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32)
target/arm/tcg/translate-a64.c
+15
@@ -6619,6 +6619,21 @@ static gen_helper_gvec_3_ptr * const f_vector_fscale[3] = {
6619
};
6620
TRANS_FEAT(FSCALE, aa64_f8cvt, do_fp3_vector, a, 0, f_vector_fscale)
6621
6622
+static bool trans_FCVTN_bh(DisasContext *s, arg_qrrr_e *a)
6623
+{
6624
+ if (!dc_isar_feature(aa64_f8cvt, s)) {
6625
+ return false;
6626
+ }
6627
+ if (fpmr_access_check(s) && fp_access_check(s)) {
6628
+ tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd),
6629
+ vec_full_reg_offset(s, a->rn),
6630
+ vec_full_reg_offset(s, a->rm),
6631
+ tcg_env, a->q ? 16 : 8, vec_full_reg_size(s),
6632
+ FPST_A64 << 2, gen_helper_gvec_fcvt_bh);
6633
+ }
6634
+ return true;
6635
+}
6636
+
6637
static bool do_fmlal(DisasContext *s, arg_qrrr_e *a, bool is_s, bool is_2)
6638
{
6639
if (fp_access_check(s)) {