@samitouri / QOSamiQemu / commits / e8ffed006b

target/arm: Separate out Neon from VFP access checks

Currently we use vfp_access_check() for AArch32 VFP and Neon instructions. This is not quite right: * there are optional CPACR.ASEDIS and HCPTR.TASE controls that allow trapping of just the Neon and not VFP instructions * Neon instructions are supposed to report a slightly different syndrome in HCR when they trap to AArch32 EL2 As a preliminary refactor so we have somewhere we can make this distinction, separate out Neon access checks into a separate neon_access_check(), which initially just calls vfp_access_check(). The set of insns this needs to cover are those described in section E1.3.9 of the DDI0487M.b Arm ARM. For us this corresponds to everything in neon-dp.decode and neon-ls.decode and thus in translate-neon.c, plus three insns that we handle in translate-vfp.c: - VDUP (general-purpose register) - VMOV (general-purpose register to scalar) byte and halfword - VMOV (scalar to general-purpose register) byte and halfword (which are the ones in that file with ARM_FEATURE_NEON checks). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702184019.3431139-2-peter.maydell@linaro.org

Peter Maydell committed Jul 2, 2026 at 19:40 UTC e8ffed006b012ca771d1807a440dc42a796bf80c
3 files changed +62 -46
target/arm/tcg/translate-a32.h
+1
@@ -33,6 +33,7 @@ void load_reg_var(DisasContext *s, TCGv_i32 var, int reg);
33 void arm_gen_condlabel(DisasContext *s);
34 bool vfp_access_check(DisasContext *s);
35 bool vfp_access_check_m(DisasContext *s, bool skip_context_update);
36 +bool neon_access_check(DisasContext *s);
37 void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop);
38 void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop);
39 void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop);
target/arm/tcg/translate-neon.c
+37 -37
@@ -135,7 +135,7 @@ static bool do_neon_ddda(DisasContext *s, int q, int vd, int vn, int vm,
135 return false;
136 }
137
138 - if (!vfp_access_check(s)) {
138 + if (!neon_access_check(s)) {
139 return true;
140 }
141
@@ -165,7 +165,7 @@ static bool do_neon_ddda_env(DisasContext *s, int q, int vd, int vn, int vm,
165 return false;
166 }
167
168 - if (!vfp_access_check(s)) {
168 + if (!neon_access_check(s)) {
169 return true;
170 }
171
@@ -197,7 +197,7 @@ static bool do_neon_ddda_fpst(DisasContext *s, int q, int vd, int vn, int vm,
197 return false;
198 }
199
200 - if (!vfp_access_check(s)) {
200 + if (!neon_access_check(s)) {
201 return true;
202 }
203
@@ -249,7 +249,7 @@ static bool trans_VCADD(DisasContext *s, arg_VCADD *a)
249 return false;
250 }
251
252 - if (!vfp_access_check(s)) {
252 + if (!neon_access_check(s)) {
253 return true;
254 }
255
@@ -319,7 +319,7 @@ static bool trans_VFML(DisasContext *s, arg_VFML *a)
319 return false;
320 }
321
322 - if (!vfp_access_check(s)) {
322 + if (!neon_access_check(s)) {
323 return true;
324 }
325
@@ -413,7 +413,7 @@ static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a)
413 return false;
414 }
415
416 - if (!vfp_access_check(s)) {
416 + if (!neon_access_check(s)) {
417 return true;
418 }
419
@@ -506,7 +506,7 @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a)
506 return false;
507 }
508
509 - if (!vfp_access_check(s)) {
509 + if (!neon_access_check(s)) {
510 return true;
511 }
512
@@ -617,7 +617,7 @@ static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a)
617 }
618 }
619
620 - if (!vfp_access_check(s)) {
620 + if (!neon_access_check(s)) {
621 return true;
622 }
623
@@ -714,7 +714,7 @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a)
714 return false;
715 }
716
717 - if (!vfp_access_check(s)) {
717 + if (!neon_access_check(s)) {
718 return true;
719 }
720
@@ -798,7 +798,7 @@ static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn)
798 return false;
799 }
800
801 - if (!vfp_access_check(s)) {
801 + if (!neon_access_check(s)) {
802 return true;
803 }
804
@@ -1076,7 +1076,7 @@ static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn)
1076 return false;
1077 }
1078
1079 - if (!vfp_access_check(s)) {
1079 + if (!neon_access_check(s)) {
1080 return true;
1081 }
1082
@@ -1126,7 +1126,7 @@ static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a,
1126 return false;
1127 }
1128
1129 - if (!vfp_access_check(s)) {
1129 + if (!neon_access_check(s)) {
1130 return true;
1131 }
1132
@@ -1177,7 +1177,7 @@ static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a,
1177 return false;
1178 }
1179
1180 - if (!vfp_access_check(s)) {
1180 + if (!neon_access_check(s)) {
1181 return true;
1182 }
1183
@@ -1302,7 +1302,7 @@ static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a,
1302 return false;
1303 }
1304
1305 - if (!vfp_access_check(s)) {
1305 + if (!neon_access_check(s)) {
1306 return true;
1307 }
1308
@@ -1392,7 +1392,7 @@ static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a,
1392 return false;
1393 }
1394
1395 - if (!vfp_access_check(s)) {
1395 + if (!neon_access_check(s)) {
1396 return true;
1397 }
1398
@@ -1436,7 +1436,7 @@ static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a,
1436 return false;
1437 }
1438
1439 - if (!vfp_access_check(s)) {
1439 + if (!neon_access_check(s)) {
1440 return true;
1441 }
1442
@@ -1499,7 +1499,7 @@ static bool do_prewiden_3d(DisasContext *s, arg_3diff *a,
1499 return false;
1500 }
1501
1502 - if (!vfp_access_check(s)) {
1502 + if (!neon_access_check(s)) {
1503 return true;
1504 }
1505
@@ -1606,7 +1606,7 @@ static bool do_narrow_3d(DisasContext *s, arg_3diff *a,
1606 return false;
1607 }
1608
1609 - if (!vfp_access_check(s)) {
1609 + if (!neon_access_check(s)) {
1610 return true;
1611 }
1612
@@ -1696,7 +1696,7 @@ static bool do_long_3d(DisasContext *s, arg_3diff *a,
1696 return false;
1697 }
1698
1699 - if (!vfp_access_check(s)) {
1699 + if (!neon_access_check(s)) {
1700 return true;
1701 }
1702
@@ -1967,7 +1967,7 @@ static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a)
1967 return false;
1968 }
1969
1970 - if (!vfp_access_check(s)) {
1970 + if (!neon_access_check(s)) {
1971 return true;
1972 }
1973
@@ -2041,7 +2041,7 @@ static bool do_2scalar(DisasContext *s, arg_2scalar *a,
2041 return false;
2042 }
2043
2044 - if (!vfp_access_check(s)) {
2044 + if (!neon_access_check(s)) {
2045 return true;
2046 }
2047
@@ -2139,7 +2139,7 @@ static bool do_2scalar_fp_vec(DisasContext *s, arg_2scalar *a,
2139 return false;
2140 }
2141
2142 - if (!vfp_access_check(s)) {
2142 + if (!neon_access_check(s)) {
2143 return true;
2144 }
2145
@@ -2236,7 +2236,7 @@ static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a,
2236 return false;
2237 }
2238
2239 - if (!vfp_access_check(s)) {
2239 + if (!neon_access_check(s)) {
2240 return true;
2241 }
2242
@@ -2307,7 +2307,7 @@ static bool do_2scalar_long(DisasContext *s, arg_2scalar *a,
2307 return false;
2308 }
2309
2310 - if (!vfp_access_check(s)) {
2310 + if (!neon_access_check(s)) {
2311 return true;
2312 }
2313
@@ -2451,7 +2451,7 @@ static bool trans_VEXT(DisasContext *s, arg_VEXT *a)
2451 return false;
2452 }
2453
2454 - if (!vfp_access_check(s)) {
2454 + if (!neon_access_check(s)) {
2455 return true;
2456 }
2457
@@ -2520,7 +2520,7 @@ static bool trans_VTBL(DisasContext *s, arg_VTBL *a)
2520 return false;
2521 }
2522
2523 - if (!vfp_access_check(s)) {
2523 + if (!neon_access_check(s)) {
2524 return true;
2525 }
2526
@@ -2555,7 +2555,7 @@ static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a)
2555 return false;
2556 }
2557
2558 - if (!vfp_access_check(s)) {
2558 + if (!neon_access_check(s)) {
2559 return true;
2560 }
2561
@@ -2591,7 +2591,7 @@ static bool do_zip_uzp(DisasContext *s, arg_2misc *a,
2591 return false;
2592 }
2593
2594 - if (!vfp_access_check(s)) {
2594 + if (!neon_access_check(s)) {
2595 return true;
2596 }
2597
@@ -2660,7 +2660,7 @@ static bool do_vmovn(DisasContext *s, arg_2misc *a,
2660 return false;
2661 }
2662
2663 - if (!vfp_access_check(s)) {
2663 + if (!neon_access_check(s)) {
2664 return true;
2665 }
2666
@@ -2724,7 +2724,7 @@ static bool trans_VSHLL(DisasContext *s, arg_2misc *a)
2724 return false;
2725 }
2726
2727 - if (!vfp_access_check(s)) {
2727 + if (!neon_access_check(s)) {
2728 return true;
2729 }
2730
@@ -2764,7 +2764,7 @@ static bool trans_VCVT_B16_F32(DisasContext *s, arg_2misc *a)
2764 return false;
2765 }
2766
2767 - if (!vfp_access_check(s)) {
2767 + if (!neon_access_check(s)) {
2768 return true;
2769 }
2770
@@ -2804,7 +2804,7 @@ static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a)
2804 return false;
2805 }
2806
2807 - if (!vfp_access_check(s)) {
2807 + if (!neon_access_check(s)) {
2808 return true;
2809 }
2810
@@ -2850,7 +2850,7 @@ static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a)
2850 return false;
2851 }
2852
2853 - if (!vfp_access_check(s)) {
2853 + if (!neon_access_check(s)) {
2854 return true;
2855 }
2856
@@ -2900,7 +2900,7 @@ static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn)
2900 return false;
2901 }
2902
2903 - if (!vfp_access_check(s)) {
2903 + if (!neon_access_check(s)) {
2904 return true;
2905 }
2906
@@ -3028,7 +3028,7 @@ static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn)
3028 return false;
3029 }
3030
3031 - if (!vfp_access_check(s)) {
3031 + if (!neon_access_check(s)) {
3032 return true;
3033 }
3034
@@ -3232,7 +3232,7 @@ static bool trans_VSWP(DisasContext *s, arg_2misc *a)
3232 return false;
3233 }
3234
3235 - if (!vfp_access_check(s)) {
3235 + if (!neon_access_check(s)) {
3236 return true;
3237 }
3238
@@ -3305,7 +3305,7 @@ static bool trans_VTRN(DisasContext *s, arg_2misc *a)
3305 return false;
3306 }
3307
3308 - if (!vfp_access_check(s)) {
3308 + if (!neon_access_check(s)) {
3309 return true;
3310 }
3311
target/arm/tcg/translate-vfp.c
+24 -9
@@ -303,6 +303,17 @@ bool vfp_access_check(DisasContext *s)
303 }
304 }
305
306 +/*
307 + * Access check for Neon; this is for instructions which can be
308 + * trapped by CPACR.ASEDIS and HCPTR.TASE. Support for those traps
309 + * is optional and we currently do not implement them, so this
310 + * is identical to a VFP access check for now.
311 + */
312 +bool neon_access_check(DisasContext *s)
313 +{
314 + return vfp_access_check(s);
315 +}
316 +
317 static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
318 {
319 uint32_t rd, rn, rm;
@@ -620,15 +631,17 @@ static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a)
631 {
632 /* VMOV scalar to general purpose register */
633 TCGv_i32 tmp;
634 + bool insn_is_neon = false;
635
636 /*
637 * SIZE == MO_32 is a VFP instruction; otherwise NEON. MVE has
638 * all sizes, whether the CPU has fp or not.
639 */
640 if (!dc_isar_feature(aa32_mve, s)) {
629 - if (a->size == MO_32
630 - ? !dc_isar_feature(aa32_fpsp_v2, s)
631 - : !arm_dc_feature(s, ARM_FEATURE_NEON)) {
641 + insn_is_neon = a->size != MO_32;
642 + if (insn_is_neon
643 + ? !arm_dc_feature(s, ARM_FEATURE_NEON)
644 + : !dc_isar_feature(aa32_fpsp_v2, s)) {
645 return false;
646 }
647 }
@@ -644,7 +657,7 @@ static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a)
657 }
658 }
659
647 - if (!vfp_access_check(s)) {
660 + if (!(insn_is_neon ? neon_access_check(s) : vfp_access_check(s))) {
661 return true;
662 }
663
@@ -665,15 +678,17 @@ static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a)
678 {
679 /* VMOV general purpose register to scalar */
680 TCGv_i32 tmp;
681 + bool insn_is_neon = false;
682
683 /*
684 * SIZE == MO_32 is a VFP instruction; otherwise NEON. MVE has
685 * all sizes, whether the CPU has fp or not.
686 */
687 if (!dc_isar_feature(aa32_mve, s)) {
674 - if (a->size == MO_32
675 - ? !dc_isar_feature(aa32_fpsp_v2, s)
676 - : !arm_dc_feature(s, ARM_FEATURE_NEON)) {
688 + insn_is_neon = a->size != MO_32;
689 + if (insn_is_neon
690 + ? !arm_dc_feature(s, ARM_FEATURE_NEON)
691 + : !dc_isar_feature(aa32_fpsp_v2, s)) {
692 return false;
693 }
694 }
@@ -689,7 +704,7 @@ static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a)
704 }
705 }
706
692 - if (!vfp_access_check(s)) {
707 + if (!(insn_is_neon ? neon_access_check(s) : vfp_access_check(s))) {
708 return true;
709 }
710
@@ -736,7 +751,7 @@ static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
751 size = 2;
752 }
753
739 - if (!vfp_access_check(s)) {
754 + if (!neon_access_check(s)) {
755 return true;
756 }
757