@samitouri / QOSamiQemu / commits / ebf25be58f

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;