@samitouri / QOSamiQemu / commits / 21e726d226

target/arm: Implement FTMOPA (non-widening, FP32)

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

Richard Henderson committed Aug 11, 2026 at 20:14 UTC 21e726d226e53896a0e6dcbb732b93bcea89115e
5 files changed +92
target/arm/cpu-features.h
+5
@@ -1590,6 +1590,11 @@ static inline bool isar_feature_aa64_sme_mop4(const ARMISARegisters *id)
1590 return FIELD_EX64_IDREG(id, ID_AA64SMFR0, SMOP4);
1591 }
1592
1593 +static inline bool isar_feature_aa64_sme_tmop(const ARMISARegisters *id)
1594 +{
1595 + return FIELD_EX64_IDREG(id, ID_AA64SMFR0, STMOP);
1596 +}
1597 +
1598 static inline bool isar_feature_aa64_ssve_aes(const ARMISARegisters *id)
1599 {
1600 return FIELD_EX64_IDREG(id, ID_AA64SMFR0, AES);
target/arm/tcg/helper-sme-defs.h
+2
@@ -404,3 +404,5 @@ DEF_HELPER_FLAGS_4(sme_usmop4a_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
404 DEF_HELPER_FLAGS_4(sme_usmop4s_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
405 DEF_HELPER_FLAGS_4(sme_usmop4a_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
406 DEF_HELPER_FLAGS_4(sme_usmop4s_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
407 +
408 +DEF_HELPER_FLAGS_6(sme_ftmopa_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fpst, i32)
target/arm/tcg/sme.decode
+10
@@ -1131,3 +1131,13 @@ UMOP4_dh 1010 0001 111. ...0 0000 00.. ..0. 1... @mop4_o3
1131
1132 USMOP4_sb 1000 0001 000. ...0 1000 00.. ..0. 00.. @mop4_o2
1133 USMOP4_dh 1010 0001 110. ...0 0000 00.. ..0. 1... @mop4_o3
1134 +
1135 +# SME TMOP Sparse outer products
1136 +
1137 +&tmop zad zn zm zk idx
1138 +%tmop_zk 10:3 !function=expand_tmop_zk
1139 +
1140 +@tmop_o2 .... .... ... zm:5 ... ... .... idx:2 .. zad:2 \
1141 + &tmop zn=%zn_ax2 zk=%tmop_zk
1142 +
1143 +FTMOPA_ss 1000 0000 010 ..... 000 ... .... .. 00 .. @tmop_o2
target/arm/tcg/sme_helper.c
+49
@@ -2636,6 +2636,49 @@ void sme_mop4(void *vza, void *vzn, void *vzm, void *fn_opaque,
2636 }
2637 }
2638
2639 +/*
2640 + * Sparse outer product, non-widening. ESZ in {16, 32}.
2641 + */
2642 +static void sme_tmop(void *vza, void *vzn, void *vzm, uint64_t *zk,
2643 + void *fn_opaque, uint32_t desc, MemOp esz,
2644 + void (*fn)(void *, void *, void *, void *))
2645 +{
2646 + intptr_t oprsz = simd_maxsz(desc);
2647 + intptr_t index = simd_data(desc);
2648 + intptr_t esize = 1 << esz;
2649 + intptr_t host_adj = HOST_BIG_ENDIAN ? 8 - esize : 0;
2650 + /* Base in bits for op3[index*:csize], csize = (VL * 2) / esize. */
2651 + intptr_t ctrl_base = index * oprsz * 2;
2652 + /* Create a zero for use with the largest esz. */
2653 + uint32_t zero = 0;
2654 +
2655 + for (intptr_t row = 0; row < oprsz; row += esize) {
2656 + void *vza_row = vza + tile_vslice_offset(row);
2657 +
2658 + for (intptr_t col = 0; col < oprsz; col += esize) {
2659 + void *e2 = vzm + (col ^ host_adj);
2660 + void *e3 = vza_row + (col ^ host_adj);
2661 +
2662 + /*
2663 + * Two control bits select one element:
2664 + * Zn[row], if [0] is set,
2665 + * Zn+1[row], if [1] is set,
2666 + * 0, otherwise.
2667 + * Compute the address of that element.
2668 + */
2669 + void *e1 = &zero;
2670 + uint64_t this_ctrl = extractn(zk, (ctrl_base + 2 * col) >> esz, 2);
2671 + if (this_ctrl) {
2672 + e1 = vzn + (row ^ host_adj);
2673 + if (!(this_ctrl & 1)) {
2674 + e1 += sizeof(ARMVectorReg);
2675 + }
2676 + }
2677 + fn(e3, e1, e2, fn_opaque);
2678 + }
2679 + }
2680 +}
2681 +
2682 static void inner_fmop4a_hh(void *vd, void *vn, void *vm, void *vinfo)
2683 {
2684 float16 *d = vd, *n = vn, *m = vm;
@@ -2692,6 +2735,12 @@ void HELPER(sme_fmop4a_ss)(void *vza, void *vzn, void *vzm,
2735 sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float32), inner_fmop4a_ss);
2736 }
2737
2738 +void HELPER(sme_ftmopa_ss)(void *vza, void *vzn, void *vzm, void *vzk,
2739 + float_status *fpst, uint32_t desc)
2740 +{
2741 + sme_tmop(vza, vzn, vzm, vzk, fpst, desc, MO_32, inner_fmop4a_ss);
2742 +}
2743 +
2744 static void inner_fmop4s_ss(void *vd, void *vn, void *vm, void *vinfo)
2745 {
2746 float32 *d = vd, *n = vn, *m = vm;
target/arm/tcg/translate-sme.c
+26
@@ -31,6 +31,12 @@
31 * Include the generated decoder.
32 */
33
34 +static int expand_tmop_zk(DisasContext *s, int x)
35 +{
36 + /* Pseudocode for 1:K:1:zk. */
37 + return 0b10100 | ((x & 4) << 1) | (x & 3);
38 +}
39 +
40 #include "decode-sme.c.inc"
41
42 static bool sme2_zt0_enabled_check(DisasContext *s)
@@ -2132,3 +2138,23 @@ TRANS_FEAT(USMOP4_sb, aa64_sme_mop4, do_mop4_int, a, MO_32,
2138 a->s ? gen_helper_sme_usmop4s_sb : gen_helper_sme_usmop4a_sb)
2139 TRANS_FEAT(USMOP4_dh, aa64_sme_mop4_i16i64, do_mop4_int, a, MO_64,
2140 a->s ? gen_helper_sme_usmop4s_dh : gen_helper_sme_usmop4a_dh)
2141 +
2142 +static bool do_tmop_fp(DisasContext *s, arg_tmop *a, MemOp esz,
2143 + int e_fpst, gen_helper_gvec_4_ptr *fn)
2144 +{
2145 + if (sme_smza_enabled_check(s)) {
2146 + int svl = streaming_vec_reg_size(s);
2147 + uint32_t desc = simd_desc(svl, svl, a->idx);
2148 + TCGv_ptr za = get_tile(s, esz, a->zad);
2149 + TCGv_ptr zn = vec_full_reg_ptr(s, a->zn);
2150 + TCGv_ptr zm = vec_full_reg_ptr(s, a->zm);
2151 + TCGv_ptr zk = vec_full_reg_ptr(s, a->zm);
2152 + TCGv_ptr fpst = (e_fpst >= 0 ? fpstatus_ptr(e_fpst) : tcg_env);
2153 +
2154 + fn(za, zn, zm, zk, fpst, tcg_constant_i32(desc));
2155 + }
2156 + return true;
2157 +}
2158 +
2159 +TRANS_FEAT(FTMOPA_ss, aa64_sme_tmop, do_tmop_fp,
2160 + a, MO_32, FPST_ZA, gen_helper_sme_ftmopa_ss)