@samitouri / QOSamiQemu / commits / 379c3f5b29

target/arm: Implement FMLALB, FMLALT for AdvSIMD

Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-30-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Richard Henderson committed Jun 9, 2026 at 12:20 UTC 379c3f5b29971ee7bb6a2385406b94dc43a80bd4
5 files changed +138
target/arm/cpu-features.h
+5
@@ -1615,6 +1615,11 @@ static inline bool isar_feature_aa64_f8cvt(const ARMISARegisters *id)
1615 return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8CVT);
1616 }
1617
1618 +static inline bool isar_feature_aa64_f8fma(const ARMISARegisters *id)
1619 +{
1620 + return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8FMA);
1621 +}
1622 +
1623 /*
1624 * Combinations of feature tests, for ease of use with TRANS_FEAT.
1625 */
target/arm/tcg/a64.decode
+8
@@ -25,6 +25,7 @@
25 %esz_hsd 22:2 !function=xor_2
26 %hl 11:1 21:1
27 %hlm 11:1 20:2
28 +%hlm4 11:1 19:3
29
30 &r rn
31 &rrr rd rn rm
@@ -38,6 +39,7 @@
39 &rri_e rd rn imm esz
40 &rrr_e rd rn rm esz
41 &rrx_e rd rn rm idx esz
42 +&rxx rd rn rm idxn idxm
43 &rrrr_e rd rn rm ra esz
44 &qrr_e q rd rn esz
45 &qrri_e q rd rn imm esz
@@ -1215,6 +1217,9 @@ FSCALE 0.10 1110 1.1 ..... 11111 1 ..... ..... @qrrr_sd
1217 FCVTN_bh 0.00 1110 010 ..... 11110 1 ..... ..... @qrrr_h
1218 FCVTN_bs 0.00 1110 000 ..... 11110 1 ..... ..... @qrrr_h
1219
1220 +FMLAL_hb_v 0 idxn:1 00 1110 110 rm:5 11111 1 rn:5 rd:5 \
1221 + &rxx idxm=0
1222 +
1223 ### Advanced SIMD scalar x indexed element
1224
1225 FMUL_si 0101 1111 00 .. .... 1001 . 0 ..... ..... @rrx_h
@@ -1333,6 +1338,9 @@ SQDMLAL_vi 0.00 1111 10 . ..... 0011 . 0 ..... ..... @qrrx_s
1338 SQDMLSL_vi 0.00 1111 01 .. .... 0111 . 0 ..... ..... @qrrx_h
1339 SQDMLSL_vi 0.00 1111 10 . ..... 0111 . 0 ..... ..... @qrrx_s
1340
1341 +FMLAL_hb_vi 0 idxn:1 00 1111 11 ... rm:3 0000 . 0 rn:5 rd:5 \
1342 + &rxx idxm=%hlm4
1343 +
1344 # Floating-point conditional select
1345
1346 FCSEL 0001 1110 .. 1 rm:5 cond:4 11 rn:5 rd:5 esz=%esz_hsd
target/arm/tcg/fp8_helper.c
+106
@@ -568,3 +568,109 @@ void HELPER(sme2_fcvtn_bs)(void *vd, void *vn, CPUARMState *env, uint32_t desc)
568
569 fp8_cvt_finish(env, &ctx);
570 }
571 +
572 +typedef struct FP8MulContext {
573 + float_status stat;
574 + fp8_input_fn *fmt1;
575 + fp8_input_fn *fmt2;
576 + int scale;
577 +} FP8MulContext;
578 +
579 +static FP8MulContext fp8_mul_start(CPUARMState *env, int scale_mask)
580 +{
581 + uint64_t fpmr = env->vfp.fpmr;
582 +
583 + FP8MulContext ret = {
584 + .stat = env->vfp.fp_status[FPST_A64],
585 + .fmt1 = fp8_input_fmt[FIELD_EX64(fpmr, FPMR, F8S1)],
586 + .fmt2 = fp8_input_fmt[FIELD_EX64(fpmr, FPMR, F8S2)],
587 + .scale = -(FIELD_EX64(fpmr, FPMR, LSCALE) & scale_mask),
588 + };
589 +
590 + set_flush_to_zero(0, &ret.stat);
591 + set_flush_inputs_to_zero(0, &ret.stat);
592 + set_default_nan_mode(true, &ret.stat);
593 + set_float_rounding_mode(FIELD_EX64(fpmr, FPMR, OSM)
594 + ? float_round_nearest_even_max
595 + : float_round_nearest_even, &ret.stat);
596 +
597 + /*
598 + * FP8 multiplies don't update any of the FPSR exception flags,
599 + * so we do not need an fp8_mul_finish() to propagate status
600 + * changes back from ret.stat into env->vfp.fp_status[].
601 + */
602 + return ret;
603 +}
604 +
605 +static FloatParts64 f8dot(uint64_t a, uint64_t b, int n, FP8MulContext *ctx)
606 +{
607 + /*
608 + * Because of default_nan_mode, NaNs need no special handling.
609 + * We'll simply get the default NaN out at the end of the sequence.
610 + */
611 + FloatParts64 p0 = ctx->fmt1(a & 0xff, &ctx->stat);
612 + FloatParts64 p1 = ctx->fmt2(b & 0xff, &ctx->stat);
613 + FloatParts64 pr = parts64_mul(&p0, &p1, &ctx->stat);
614 +
615 + for (int i = 1; i < n; ++i) {
616 + p0 = ctx->fmt1(extract64(a, i * 8, 8), &ctx->stat);
617 + p1 = ctx->fmt2(extract64(b, i * 8, 8), &ctx->stat);
618 + pr = parts64_muladd(&p0, &p1, &pr, 0, &ctx->stat);
619 + }
620 + return parts64_scalbn(&pr, ctx->scale, &ctx->stat);
621 +}
622 +
623 +static float16 f8dotadd_h(uint64_t a, uint64_t b, int n, float16 c,
624 + FP8MulContext *ctx)
625 +{
626 + FloatParts64 p0 = f8dot(a, b, n, ctx);
627 + FloatParts64 p1 = float16_unpack_canonical(c, &ctx->stat);
628 +
629 + p0 = parts64_addsub(&p0, &p1, &ctx->stat, false);
630 + return float16_round_pack_canonical(&p0, &ctx->stat);
631 +}
632 +
633 +void HELPER(gvec_fmla_hb)(void *vd, void *vn, void *vm,
634 + CPUARMState *env, uint32_t desc)
635 +{
636 + FP8MulContext ctx = fp8_mul_start(env, 0xf);
637 + bool high = extract32(desc, SIMD_DATA_SHIFT, 1);
638 + size_t oprsz = simd_oprsz(desc);
639 + size_t nelem = oprsz / 2;
640 + uint8_t *n = vn;
641 + uint8_t *m = vm;
642 + float16 *d = vd;
643 +
644 + for (size_t i = 0; i < nelem; i++) {
645 + uint8_t e0 = n[H1(2 * i + high)];
646 + uint8_t e1 = m[H1(2 * i + high)];
647 +
648 + d[H2(i)] = f8dotadd_h(e0, e1, 1, d[H2(i)], &ctx);
649 + }
650 +
651 + clear_tail(vd, oprsz, simd_maxsz(desc));
652 +}
653 +
654 +void HELPER(gvec_fmla_idx_hb)(void *vd, void *vn, void *vm,
655 + CPUARMState *env, uint32_t desc)
656 +{
657 + FP8MulContext ctx = fp8_mul_start(env, 0xf);
658 + bool idx_n = extract32(desc, SIMD_DATA_SHIFT, 1);
659 + size_t idx_m = extract32(desc, SIMD_DATA_SHIFT + 2, 4);
660 + size_t oprsz = simd_oprsz(desc);
661 + size_t nelem = oprsz / 2;
662 + uint8_t *n = vn;
663 + uint8_t *m = vm;
664 + float16 *d = vd;
665 + size_t i = 0;
666 +
667 + do {
668 + uint8_t e1 = m[2 * i + H1(idx_m)];
669 + do {
670 + uint8_t e0 = n[H1(2 * i + idx_n)];
671 + d[H2(i)] = f8dotadd_h(e0, e1, 1, d[H2(i)], &ctx);
672 + } while (++i % 8 != 0);
673 + } while (i < nelem);
674 +
675 + clear_tail(vd, oprsz, simd_maxsz(desc));
676 +}
target/arm/tcg/helper-fp8-defs.h
+3
@@ -23,3 +23,6 @@ DEF_HELPER_FLAGS_4(sve2_fcvtnb_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
23 DEF_HELPER_FLAGS_4(sve2_fcvtnt_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
24 DEF_HELPER_FLAGS_4(sme2_fcvt_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
25 DEF_HELPER_FLAGS_4(sme2_fcvtn_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
26 +
27 +DEF_HELPER_FLAGS_5(gvec_fmla_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32)
28 +DEF_HELPER_FLAGS_5(gvec_fmla_idx_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32)
target/arm/tcg/translate-a64.c
+16
@@ -7481,6 +7481,22 @@ TRANS_FEAT(FMLSL_vi, aa64_fhm, do_fmlal_idx, a, true, false)
7481 TRANS_FEAT(FMLAL2_vi, aa64_fhm, do_fmlal_idx, a, false, true)
7482 TRANS_FEAT(FMLSL2_vi, aa64_fhm, do_fmlal_idx, a, true, true)
7483
7484 +static bool do_fmla_fp8(DisasContext *s, arg_rxx *a,
7485 + gen_helper_gvec_3_ptr *fn)
7486 +{
7487 + if (fpmr_access_check(s) && fp_access_check(s)) {
7488 + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd),
7489 + vec_full_reg_offset(s, a->rn),
7490 + vec_full_reg_offset(s, a->rm),
7491 + tcg_env, 16, vec_full_reg_size(s),
7492 + a->idxn | (a->idxm << 2), fn);
7493 + }
7494 + return true;
7495 +}
7496 +
7497 +TRANS_FEAT(FMLAL_hb_v, aa64_f8fma, do_fmla_fp8, a, gen_helper_gvec_fmla_hb)
7498 +TRANS_FEAT(FMLAL_hb_vi, aa64_f8fma, do_fmla_fp8, a, gen_helper_gvec_fmla_idx_hb)
7499 +
7500 static bool do_int3_vector_idx(DisasContext *s, arg_qrrx_e *a,
7501 gen_helper_gvec_3 * const fns[2])
7502 {