@samitouri / QOSamiQemu / commits / 9c15806307

target/arm: Implement LUTI2, LUTI4 for SVE

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

Richard Henderson committed Jun 9, 2026 at 12:20 UTC 9c15806307f29a9f9a3a251cf0b6c5c3c02fa648
5 files changed +86 -1
target/arm/cpu-features.h
+6
@@ -1674,6 +1674,12 @@ isar_feature_aa64_sme2_or_sve2_f8cvt(const ARMISARegisters *id)
1674 return isar_feature_aa64_sme2_or_sve2(id) && isar_feature_aa64_f8cvt(id);
1675 }
1676
1677 +static inline bool
1678 +isar_feature_aa64_sme2_or_sve2_lut(const ARMISARegisters *id)
1679 +{
1680 + return isar_feature_aa64_sme2_or_sve2(id) && isar_feature_aa64_lut(id);
1681 +}
1682 +
1683 /*
1684 * Feature tests for "does this exist in either 32-bit or 64-bit?"
1685 */
target/arm/tcg/sve.decode
+10 -1
@@ -31,6 +31,7 @@
31 %dtype_23_13 23:2 13:2
32 %index3_22_19 22:1 19:2
33 %index3_22_17 22:1 17:2
34 +%index3_22_12 22:2 12:1
35 %index3_19_11 19:2 11:1
36 %index2_20_11 20:1 11:1
37
@@ -1737,11 +1738,19 @@ RSUBHNT 01000101 .. 1 ..... 011 111 ..... ..... @rd_rn_rm
1738 MATCH 01000101 .. 1 ..... 100 ... ..... 0 .... @pd_pg_rn_rm
1739 NMATCH 01000101 .. 1 ..... 100 ... ..... 1 .... @pd_pg_rn_rm
1740
1740 -### SVE2 Histogram Computation
1741 +### SVE2 Histogram Computation and Lookup Table
1742
1743 HISTCNT 01000101 .. 1 ..... 110 ... ..... ..... @rd_pg_rn_rm
1744 HISTSEG 01000101 .. 1 ..... 101 000 ..... ..... @rd_rn_rm
1745
1746 +LUTI2_1b 01000101 index:2 1 rm:5 101100 rn:5 rd:5 &rrx_esz esz=0
1747 +LUTI2_1h 01000101 .. 1 rm:5 101.10 rn:5 rd:5 \
1748 + &rrx_esz esz=1 index=%index3_22_12
1749 +
1750 +LUTI4_1b 01000101 index:1 11 rm:5 101001 rn:5 rd:5 &rrx_esz esz=0
1751 +LUTI4_1h 01000101 index:2 1 rm:5 101111 rn:5 rd:5 &rrx_esz esz=1
1752 +LUTI4_2h 01000101 index:2 1 rm:5 101101 rn:5 rd:5 &rrx_esz esz=1
1753 +
1754 ## SVE2 floating-point pairwise operations
1755
1756 FADDP 01100100 .. 010 00 0 100 ... ..... ..... @rdn_pg_rm
target/arm/tcg/translate-a64.c
+1
@@ -10917,6 +10917,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
10917 dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16;
10918 dc->svl = (EX_TBFLAG_A64(tb_flags, SVL) + 1) * 16;
10919 dc->max_svl = arm_cpu->sme_max_vq * 16;
10920 + dc->max_any_vl = MAX(dc->max_svl, arm_cpu->sve_max_vq * 16);
10921 dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE);
10922 dc->bt = EX_TBFLAG_A64(tb_flags, BT);
10923 dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE);
target/arm/tcg/translate-sve.c
+68
@@ -8287,3 +8287,71 @@ TRANS_FEAT(LD1_zcrr_stride, aa64_sme2, gen_ldst_zcrr_c, a, false, true)
8287 TRANS_FEAT(LD1_zcri_stride, aa64_sme2, gen_ldst_zcri_c, a, false, true)
8288 TRANS_FEAT(ST1_zcrr_stride, aa64_sme2, gen_ldst_zcrr_c, a, true, true)
8289 TRANS_FEAT(ST1_zcri_stride, aa64_sme2, gen_ldst_zcri_c, a, true, true)
8290 +
8291 +TRANS_FEAT_STREAMING_IF(LUTI2_1b, aa64_sme2_or_sve2_lut, aa64_sme2,
8292 + gen_gvec_ool_zzz, gen_helper_gvec_luti2_b,
8293 + a->rd, a->rn, a->rm, a->index)
8294 +TRANS_FEAT_STREAMING_IF(LUTI2_1h, aa64_sme2_or_sve2_lut, aa64_sme2,
8295 + gen_gvec_ool_zzz, gen_helper_gvec_luti2_h,
8296 + a->rd, a->rn, a->rm, a->index)
8297 +TRANS_FEAT_STREAMING_IF(LUTI4_1b, aa64_sme2_or_sve2_lut, aa64_sme2,
8298 + gen_gvec_ool_zzz, gen_helper_gvec_luti4_b,
8299 + a->rd, a->rn, a->rm, a->index)
8300 +
8301 +static bool trans_LUTI4_1h(DisasContext *s, arg_LUTI4_1h *a)
8302 +{
8303 + if (!dc_isar_feature(aa64_sme2_or_sve2_lut, s)) {
8304 + return false;
8305 + }
8306 + s->is_nonstreaming = !dc_isar_feature(aa64_sme2, s);
8307 +
8308 + /*
8309 + * The MaxImplementedAnyVL check happens in the decode pseudocode,
8310 + * before the Check*SVEEnabled check in the operation pseudocode.
8311 + */
8312 + if (s->max_any_vl < 32) {
8313 + unallocated_encoding(s);
8314 + } else if (sve_access_check(s)) {
8315 + unsigned vsz = vec_full_reg_size(s);
8316 +
8317 + /* Then there's a second check against CurrentVL. */
8318 + if (vsz < 32) {
8319 + unallocated_encoding(s);
8320 + } else {
8321 + tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd),
8322 + vec_full_reg_offset(s, a->rn),
8323 + vec_full_reg_offset(s, a->rm),
8324 + vsz, vsz, a->index,
8325 + gen_helper_gvec_luti4_h);
8326 + }
8327 + }
8328 + return true;
8329 +}
8330 +
8331 +static bool trans_LUTI4_2h(DisasContext *s, arg_LUTI4_2h *a)
8332 +{
8333 + if (!dc_isar_feature(aa64_sme2_or_sve2_lut, s)) {
8334 + return false;
8335 + }
8336 + s->is_nonstreaming = !dc_isar_feature(aa64_sme2, s);
8337 +
8338 + if (sve_access_check(s)) {
8339 + unsigned vsz = vec_full_reg_size(s);
8340 + /*
8341 + * (Ab)use preg_tmp to merge two disjoint 128-bit quantities
8342 + * into a sequential 256-bit table.
8343 + */
8344 + QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, vfp.preg_tmp) < 32);
8345 + unsigned tmp_ofs = offsetof(CPUARMState, vfp.preg_tmp);
8346 + unsigned rn0_ofs = vec_full_reg_offset(s, a->rn);
8347 + unsigned rn1_ofs = vec_full_reg_offset(s, (a->rn + 1) % 32);
8348 +
8349 + tcg_gen_gvec_mov(MO_64, tmp_ofs, rn0_ofs, 16, 16);
8350 + tcg_gen_gvec_mov(MO_64, tmp_ofs + 16, rn1_ofs, 16, 16);
8351 +
8352 + tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), tmp_ofs,
8353 + vec_full_reg_offset(s, a->rm),
8354 + vsz, vsz, a->index, gen_helper_gvec_luti4_h);
8355 + }
8356 + return true;
8357 +}
target/arm/tcg/translate.h
+1
@@ -91,6 +91,7 @@ typedef struct DisasContext {
91 int vl; /* current vector length in bytes */
92 int svl; /* current streaming vector length in bytes */
93 int max_svl; /* maximum implemented streaming vector length */
94 + int max_any_vl; /* maximum implemented vector length */
95 bool vfp_enabled; /* FP enabled via FPSCR.EN */
96 int vec_len;
97 int vec_stride;