target/i386/tcg: fetch modrm early
As a first step towards handling EVEX prefixes, fetch the modrm byte before decode_ops(). This way, EVEX validation can use the mod bits: for example, APX instructions require X4=0 if the r/m operand is a register. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Paolo Bonzini committed
Dec 23, 2025 at 12:07 UTC
ebf25be58f5ecb73b97f1087323a793e8db0d7ed
1 file changed
+50
-15
target/i386/tcg/decode-new.c.inc
+50
-15
@@ -2012,9 +2012,8 @@ static void decode_root(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui
2012
static void decode_modrm(DisasContext *s, CPUX86State *env,
2013
X86DecodedInsn *decode, X86DecodedOp *op)
2014
{
2015
- int modrm = get_modrm(s, env);
2016
- int mod = (modrm >> 6) & 3;
2017
- int rm = modrm & 7;
2015
+ int mod = (s->modrm >> 6) & 3;
2016
+ int rm = s->modrm & 7;
2017
bool is_vsib = decode->e.vex_class == 12;
2018
int sib = -1;
2019
@@ -2226,11 +2225,33 @@ static bool decode_op_size(DisasContext *s, X86OpEntry *e, X86OpSize size, MemOp
2225
}
2226
}
2227
2228
+static bool op_has_modrm(X86OpType type)
2229
+{
2230
+ switch (type) {
2231
+ case X86_TYPE_C: /* REG in the modrm byte selects a control register */
2232
+ case X86_TYPE_D: /* REG in the modrm byte selects a debug register */
2233
+ case X86_TYPE_E: /* ALU modrm operand */
2234
+ case X86_TYPE_EM: /* modrm byte selects an ALU memory operand */
2235
+ case X86_TYPE_G: /* REG in the modrm byte selects a GPR */
2236
+ case X86_TYPE_M: /* modrm byte selects a memory operand */
2237
+ case X86_TYPE_nop: /* modrm operand decoded but not fetched */
2238
+ case X86_TYPE_N: /* R/M in the modrm byte selects an MMX register */
2239
+ case X86_TYPE_P: /* REG in the modrm byte selects an MMX register */
2240
+ case X86_TYPE_Q: /* MMX modrm operand */
2241
+ case X86_TYPE_R: /* R/M in the modrm byte selects a register */
2242
+ case X86_TYPE_U: /* R/M in the modrm byte selects an XMM/YMM register */
2243
+ case X86_TYPE_V: /* reg in the modrm byte selects an XMM/YMM register */
2244
+ case X86_TYPE_WM: /* modrm byte selects an XMM/YMM memory operand */
2245
+ case X86_TYPE_W: /* XMM/YMM modrm operand */
2246
+ return true;
2247
+ default:
2248
+ return false;
2249
+ }
2250
+}
2251
+
2252
static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode,
2253
X86DecodedOp *op, X86OpType type, int b)
2254
{
2232
- int modrm;
2233
-
2255
switch (type) {
2256
case X86_TYPE_None: /* Implicit or absent */
2257
case X86_TYPE_A: /* Implicit */
@@ -2246,7 +2267,7 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode,
2267
2268
case X86_TYPE_C: /* REG in the modrm byte selects a control register */
2269
op->unit = X86_OP_CR;
2249
- op->n = ((get_modrm(s, env) >> 3) & 7) | REX_R(s);
2270
+ op->n = ((s->modrm >> 3) & 7) | REX_R(s);
2271
if (op->n == 0 && (s->prefix & PREFIX_LOCK) &&
2272
(s->cpuid_ext3_features & CPUID_EXT3_CR8LEG)) {
2273
op->n = 8;
@@ -2262,7 +2283,7 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode,
2283
2284
case X86_TYPE_D: /* REG in the modrm byte selects a debug register */
2285
op->unit = X86_OP_DR;
2265
- op->n = ((get_modrm(s, env) >> 3) & 7) | REX_R(s);
2286
+ op->n = ((s->modrm >> 3) & 7) | REX_R(s);
2287
if (op->n >= 8) {
2288
/*
2289
* illegal opcode. The DR4 and DR5 case is checked in the generated
@@ -2281,14 +2302,14 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode,
2302
2303
case X86_TYPE_S: /* reg selects a segment register */
2304
op->unit = X86_OP_SEG;
2284
- op->n = (get_modrm(s, env) >> 3) & 7;
2305
+ op->n = (s->modrm >> 3) & 7;
2306
/* Values outside [CDEFGS]S, as well as storing to CS, are invalid. */
2307
if (op->n >= 6 || (op->n == R_CS && op == &decode->op[0])) {
2308
return false;
2309
}
2310
break;
2311
2291
- case X86_TYPE_P:
2312
+ case X86_TYPE_P: /* REG in the modrm byte selects an MMX register */
2313
op->unit = X86_OP_MMX;
2314
goto get_reg;
2315
@@ -2300,7 +2321,7 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode,
2321
op->unit = X86_OP_SSE;
2322
}
2323
get_reg:
2303
- op->n = ((get_modrm(s, env) >> 3) & 7);
2324
+ op->n = ((s->modrm >> 3) & 7);
2325
if (op->unit != X86_OP_MMX) {
2326
op->n |= REX_R(s);
2327
}
@@ -2339,8 +2360,7 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode,
2360
case X86_TYPE_R: /* R/M in the modrm byte selects a register */
2361
op->unit = X86_OP_INT;
2362
get_modrm_reg:
2342
- modrm = get_modrm(s, env);
2343
- if ((modrm >> 6) != 3) {
2363
+ if ((s->modrm >> 6) != 3) {
2364
return false;
2365
}
2366
goto get_modrm;
@@ -2354,8 +2374,7 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode,
2374
/* fall through */
2375
case X86_TYPE_M: /* modrm byte selects a memory operand */
2376
get_modrm_mem:
2357
- modrm = get_modrm(s, env);
2358
- if ((modrm >> 6) == 3) {
2377
+ if ((s->modrm >> 6) == 3) {
2378
return false;
2379
}
2380
/* fall through */
@@ -2463,7 +2482,7 @@ static bool decode_insn(DisasContext *s, CPUX86State *env, X86DecodeFunc decode_
2482
return false;
2483
}
2484
2466
- /* First compute size of operands in order to initialize s->rip_offset. */
2485
+ /* Compute size of operands here in order to initialize s->rip_offset. */
2486
if (e->op0 != X86_TYPE_None) {
2487
if (!decode_op_size(s, e, e->s0, &decode->op[0].ot)) {
2488
return false;
@@ -2496,6 +2515,13 @@ static bool decode_insn(DisasContext *s, CPUX86State *env, X86DecodeFunc decode_
2515
assert(e->op3 == X86_TYPE_I && e->s3 == X86_SIZE_b);
2516
s->rip_offset += 1;
2517
}
2518
+ return true;
2519
+}
2520
+
2521
+static bool decode_ops(DisasContext *s, CPUX86State *env, X86DecodeFunc decode_func,
2522
+ X86DecodedInsn *decode)
2523
+{
2524
+ X86OpEntry *e = &decode->e;
2525
2526
if (e->op0 != X86_TYPE_None &&
2527
!decode_op(s, env, decode, &decode->op[0], e->op0, decode->b)) {
@@ -2993,6 +3019,15 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
3019
}
3020
}
3021
3022
+ if (op_has_modrm(decode.e.op0) || op_has_modrm(decode.e.op1) ||
3023
+ op_has_modrm(decode.e.op2)) {
3024
+ get_modrm(s, env);
3025
+ }
3026
+
3027
+ if (!decode_ops(s, env, decode_func, &decode)) {
3028
+ goto illegal_op;
3029
+ }
3030
+
3031
switch (decode.e.special) {
3032
case X86_SPECIAL_None:
3033
break;