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;