target/i386/tcg: move VEX validation early
Perform the X86_VEX_REPScalar transformation on X86OpEntry instead of X86DecodedOp; everything else can be checked equally well before immediates are fetched etc. This is especially important for APX, which may decode operands differently depending on the NDD bit: if EVEX.NDD=0, VEX.vvvv is ignored and must be zero. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Paolo Bonzini committed
Dec 23, 2025 at 11:51 UTC
b7d4ec4832d427208717c8b726d6dbb214d851a7
1 file changed
+30
-24
target/i386/tcg/decode-new.c.inc
+30
-24
@@ -2542,6 +2542,22 @@ static bool decode_ops(DisasContext *s, CPUX86State *env, X86DecodeFunc decode_f
2542
decode->immediate = insn_get_signed(env, s, MO_8);
2543
}
2544
2545
+ if (e->vex_class == 12) {
2546
+ /* Check no overlap between registers. */
2547
+ if (!decode->op[0].has_ea &&
2548
+ (decode->op[0].n == decode->mem.index || decode->op[0].n == decode->op[1].n)) {
2549
+ return false;
2550
+ }
2551
+ assert(!decode->op[1].has_ea);
2552
+ if (decode->op[1].n == decode->mem.index) {
2553
+ return false;
2554
+ }
2555
+ if (!decode->op[2].has_ea &&
2556
+ (decode->op[2].n == decode->mem.index || decode->op[2].n == decode->op[1].n)) {
2557
+ return false;
2558
+ }
2559
+ }
2560
+
2561
return true;
2562
}
2563
@@ -2648,9 +2664,9 @@ static bool validate_vex(DisasContext *s, X86DecodedInsn *decode)
2664
if (s->vex_l) {
2665
goto illegal;
2666
}
2651
- assert(decode->e.s2 == X86_SIZE_x);
2652
- if (decode->op[2].has_ea) {
2653
- decode->op[2].ot = s->prefix & PREFIX_REPZ ? MO_32 : MO_64;
2667
+ assert(e->op2 == X86_TYPE_W && e->s2 == X86_SIZE_x);
2668
+ if ((s->modrm >> 6) != 3) {
2669
+ e->s2 = s->prefix & PREFIX_REPNZ ? X86_SIZE_sd : X86_SIZE_ss;
2670
}
2671
}
2672
break;
@@ -2667,10 +2683,7 @@ static bool validate_vex(DisasContext *s, X86DecodedInsn *decode)
2683
2684
switch (e->vex_class) {
2685
case 0:
2670
- if (s->prefix & PREFIX_VEX) {
2671
- goto illegal;
2672
- }
2673
- return true;
2686
+ g_assert_not_reached();
2687
case 1:
2688
case 2:
2689
case 3:
@@ -2695,19 +2708,6 @@ static bool validate_vex(DisasContext *s, X86DecodedInsn *decode)
2708
goto illegal;
2709
}
2710
2698
- /* Check no overlap between registers. */
2699
- if (!decode->op[0].has_ea &&
2700
- (decode->op[0].n == decode->mem.index || decode->op[0].n == decode->op[1].n)) {
2701
- goto illegal;
2702
- }
2703
- assert(!decode->op[1].has_ea);
2704
- if (decode->op[1].n == decode->mem.index) {
2705
- goto illegal;
2706
- }
2707
- if (!decode->op[2].has_ea &&
2708
- (decode->op[2].n == decode->mem.index || decode->op[2].n == decode->op[1].n)) {
2709
- goto illegal;
2710
- }
2711
/* fall through */
2712
case 6:
2713
case 11:
@@ -3024,6 +3024,16 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
3024
get_modrm(s, env);
3025
}
3026
3027
+ if (decode.e.vex_class == 0) {
3028
+ if (s->prefix & PREFIX_VEX) {
3029
+ goto illegal_op;
3030
+ }
3031
+ } else {
3032
+ if (!validate_vex(s, &decode)) {
3033
+ return;
3034
+ }
3035
+ }
3036
+
3037
if (!decode_ops(s, env, decode_func, &decode)) {
3038
goto illegal_op;
3039
}
@@ -3085,10 +3095,6 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
3095
goto illegal_op;
3096
}
3097
3088
- if (!validate_vex(s, &decode)) {
3089
- return;
3090
- }
3091
-
3098
/*
3099
* Checks that result in #GP or VMEXIT come second. Intercepts are
3100
* generally checked after non-memory exceptions (i.e. after all