From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Subject: [PATCH 18/18] target/i386/tcg: move fetch code out of translate.c
Date: Wed, 10 Dec 2025 14:16:53 +0100 [thread overview]
Message-ID: <20251210131653.852163-19-pbonzini@redhat.com> (raw)
In-Reply-To: <20251210131653.852163-1-pbonzini@redhat.com>
Let translate.c only concern itself with TCG code generation. Move everything
that uses CPUX86State*, as well as gen_lea_modrm_0 now that it is only used
to fill decode->mem, to decode-new.c.inc.
While at it also rename gen_lea_modrm_0.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/tcg/translate.c | 271 ------------------------------
target/i386/tcg/decode-new.c.inc | 277 ++++++++++++++++++++++++++++++-
2 files changed, 274 insertions(+), 274 deletions(-)
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 17ad4ccacaf..a905efdfbbd 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -1644,182 +1644,6 @@ static TCGv gen_shiftd_rm_T1(DisasContext *s, MemOp ot,
return cc_src;
}
-#define X86_MAX_INSN_LENGTH 15
-
-static uint64_t advance_pc(CPUX86State *env, DisasContext *s, int num_bytes)
-{
- uint64_t pc = s->pc;
-
- /* This is a subsequent insn that crosses a page boundary. */
- if (s->base.num_insns > 1 &&
- !translator_is_same_page(&s->base, s->pc + num_bytes - 1)) {
- siglongjmp(s->jmpbuf, 2);
- }
-
- s->pc += num_bytes;
- if (unlikely(cur_insn_len(s) > X86_MAX_INSN_LENGTH)) {
- /* If the instruction's 16th byte is on a different page than the 1st, a
- * page fault on the second page wins over the general protection fault
- * caused by the instruction being too long.
- * This can happen even if the operand is only one byte long!
- */
- if (((s->pc - 1) ^ (pc - 1)) & TARGET_PAGE_MASK) {
- (void)translator_ldub(env, &s->base,
- (s->pc - 1) & TARGET_PAGE_MASK);
- }
- siglongjmp(s->jmpbuf, 1);
- }
-
- return pc;
-}
-
-static inline uint8_t x86_ldub_code(CPUX86State *env, DisasContext *s)
-{
- return translator_ldub(env, &s->base, advance_pc(env, s, 1));
-}
-
-static inline uint16_t x86_lduw_code(CPUX86State *env, DisasContext *s)
-{
- return translator_lduw(env, &s->base, advance_pc(env, s, 2));
-}
-
-static inline uint32_t x86_ldl_code(CPUX86State *env, DisasContext *s)
-{
- return translator_ldl(env, &s->base, advance_pc(env, s, 4));
-}
-
-#ifdef TARGET_X86_64
-static inline uint64_t x86_ldq_code(CPUX86State *env, DisasContext *s)
-{
- return translator_ldq(env, &s->base, advance_pc(env, s, 8));
-}
-#endif
-
-/* Decompose an address. */
-
-static AddressParts gen_lea_modrm_0(CPUX86State *env, DisasContext *s,
- int modrm, bool is_vsib)
-{
- int def_seg, base, index, scale, mod, rm;
- target_long disp;
- bool havesib;
-
- def_seg = R_DS;
- index = -1;
- scale = 0;
- disp = 0;
-
- mod = (modrm >> 6) & 3;
- rm = modrm & 7;
- base = rm | REX_B(s);
-
- if (mod == 3) {
- /* Normally filtered out earlier, but including this path
- simplifies multi-byte nop, as well as bndcl, bndcu, bndcn. */
- goto done;
- }
-
- switch (s->aflag) {
- case MO_64:
- case MO_32:
- havesib = 0;
- if (rm == 4) {
- int code = x86_ldub_code(env, s);
- scale = (code >> 6) & 3;
- index = ((code >> 3) & 7) | REX_X(s);
- if (index == 4 && !is_vsib) {
- index = -1; /* no index */
- }
- base = (code & 7) | REX_B(s);
- havesib = 1;
- }
-
- switch (mod) {
- case 0:
- if ((base & 7) == 5) {
- base = -1;
- disp = (int32_t)x86_ldl_code(env, s);
- if (CODE64(s) && !havesib) {
- base = -2;
- disp += s->pc + s->rip_offset;
- }
- }
- break;
- case 1:
- disp = (int8_t)x86_ldub_code(env, s);
- break;
- default:
- case 2:
- disp = (int32_t)x86_ldl_code(env, s);
- break;
- }
-
- /* For correct popl handling with esp. */
- if (base == R_ESP && s->popl_esp_hack) {
- disp += s->popl_esp_hack;
- }
- if (base == R_EBP || base == R_ESP) {
- def_seg = R_SS;
- }
- break;
-
- case MO_16:
- if (mod == 0) {
- if (rm == 6) {
- base = -1;
- disp = x86_lduw_code(env, s);
- break;
- }
- } else if (mod == 1) {
- disp = (int8_t)x86_ldub_code(env, s);
- } else {
- disp = (int16_t)x86_lduw_code(env, s);
- }
-
- switch (rm) {
- case 0:
- base = R_EBX;
- index = R_ESI;
- break;
- case 1:
- base = R_EBX;
- index = R_EDI;
- break;
- case 2:
- base = R_EBP;
- index = R_ESI;
- def_seg = R_SS;
- break;
- case 3:
- base = R_EBP;
- index = R_EDI;
- def_seg = R_SS;
- break;
- case 4:
- base = R_ESI;
- break;
- case 5:
- base = R_EDI;
- break;
- case 6:
- base = R_EBP;
- def_seg = R_SS;
- break;
- default:
- case 7:
- base = R_EBX;
- break;
- }
- break;
-
- default:
- g_assert_not_reached();
- }
-
- done:
- return (AddressParts){ def_seg, base, index, scale, disp };
-}
-
/* Compute the address, with a minimum number of TCG ops. */
static TCGv gen_lea_modrm_1(DisasContext *s, AddressParts a, bool is_vsib)
{
@@ -1904,79 +1728,6 @@ static void gen_st_modrm(DisasContext *s, X86DecodedInsn *decode, MemOp ot)
}
}
-static target_ulong insn_get_addr(CPUX86State *env, DisasContext *s, MemOp ot)
-{
- target_ulong ret;
-
- switch (ot) {
- case MO_8:
- ret = x86_ldub_code(env, s);
- break;
- case MO_16:
- ret = x86_lduw_code(env, s);
- break;
- case MO_32:
- ret = x86_ldl_code(env, s);
- break;
-#ifdef TARGET_X86_64
- case MO_64:
- ret = x86_ldq_code(env, s);
- break;
-#endif
- default:
- g_assert_not_reached();
- }
- return ret;
-}
-
-static inline uint32_t insn_get(CPUX86State *env, DisasContext *s, MemOp ot)
-{
- uint32_t ret;
-
- switch (ot) {
- case MO_8:
- ret = x86_ldub_code(env, s);
- break;
- case MO_16:
- ret = x86_lduw_code(env, s);
- break;
- case MO_32:
-#ifdef TARGET_X86_64
- case MO_64:
-#endif
- ret = x86_ldl_code(env, s);
- break;
- default:
- g_assert_not_reached();
- }
- return ret;
-}
-
-static target_long insn_get_signed(CPUX86State *env, DisasContext *s, MemOp ot)
-{
- target_long ret;
-
- switch (ot) {
- case MO_8:
- ret = (int8_t) x86_ldub_code(env, s);
- break;
- case MO_16:
- ret = (int16_t) x86_lduw_code(env, s);
- break;
- case MO_32:
- ret = (int32_t) x86_ldl_code(env, s);
- break;
-#ifdef TARGET_X86_64
- case MO_64:
- ret = x86_ldq_code(env, s);
- break;
-#endif
- default:
- g_assert_not_reached();
- }
- return ret;
-}
-
static void gen_conditional_jump_labels(DisasContext *s, target_long diff,
TCGLabel *not_taken, TCGLabel *taken)
{
@@ -2221,28 +1972,6 @@ static void gen_leave(DisasContext *s)
gen_op_mov_reg_v(s, a_ot, R_ESP, s->T1);
}
-/* Similarly, except that the assumption here is that we don't decode
- the instruction at all -- either a missing opcode, an unimplemented
- feature, or just a bogus instruction stream. */
-static void gen_unknown_opcode(CPUX86State *env, DisasContext *s)
-{
- gen_illegal_opcode(s);
-
- if (qemu_loglevel_mask(LOG_UNIMP)) {
- FILE *logfile = qemu_log_trylock();
- if (logfile) {
- target_ulong pc = s->base.pc_next, end = s->pc;
-
- fprintf(logfile, "ILLOPC: " TARGET_FMT_lx ":", pc);
- for (; pc < end; ++pc) {
- fprintf(logfile, " %02x", translator_ldub(env, &s->base, pc));
- }
- fprintf(logfile, "\n");
- qemu_log_unlock(logfile);
- }
- }
-}
-
/* an interrupt is different from an exception because of the
privilege checks */
static void gen_interrupt(DisasContext *s, uint8_t intno)
diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc
index 9d17bae7e75..b4aa300ab47 100644
--- a/target/i386/tcg/decode-new.c.inc
+++ b/target/i386/tcg/decode-new.c.inc
@@ -279,6 +279,130 @@
#define UNKNOWN_OPCODE ((X86OpEntry) {})
+#define X86_MAX_INSN_LENGTH 15
+
+static uint64_t advance_pc(CPUX86State *env, DisasContext *s, int num_bytes)
+{
+ uint64_t pc = s->pc;
+
+ /* This is a subsequent insn that crosses a page boundary. */
+ if (s->base.num_insns > 1 &&
+ !translator_is_same_page(&s->base, s->pc + num_bytes - 1)) {
+ siglongjmp(s->jmpbuf, 2);
+ }
+
+ s->pc += num_bytes;
+ if (unlikely(cur_insn_len(s) > X86_MAX_INSN_LENGTH)) {
+ /* If the instruction's 16th byte is on a different page than the 1st, a
+ * page fault on the second page wins over the general protection fault
+ * caused by the instruction being too long.
+ * This can happen even if the operand is only one byte long!
+ */
+ if (((s->pc - 1) ^ (pc - 1)) & TARGET_PAGE_MASK) {
+ (void)translator_ldub(env, &s->base,
+ (s->pc - 1) & TARGET_PAGE_MASK);
+ }
+ siglongjmp(s->jmpbuf, 1);
+ }
+
+ return pc;
+}
+
+static inline uint8_t x86_ldub_code(CPUX86State *env, DisasContext *s)
+{
+ return translator_ldub(env, &s->base, advance_pc(env, s, 1));
+}
+
+static inline uint16_t x86_lduw_code(CPUX86State *env, DisasContext *s)
+{
+ return translator_lduw(env, &s->base, advance_pc(env, s, 2));
+}
+
+static inline uint32_t x86_ldl_code(CPUX86State *env, DisasContext *s)
+{
+ return translator_ldl(env, &s->base, advance_pc(env, s, 4));
+}
+
+#ifdef TARGET_X86_64
+static inline uint64_t x86_ldq_code(CPUX86State *env, DisasContext *s)
+{
+ return translator_ldq(env, &s->base, advance_pc(env, s, 8));
+}
+#endif
+
+static target_ulong insn_get_addr(CPUX86State *env, DisasContext *s, MemOp ot)
+{
+ target_ulong ret;
+
+ switch (ot) {
+ case MO_8:
+ ret = x86_ldub_code(env, s);
+ break;
+ case MO_16:
+ ret = x86_lduw_code(env, s);
+ break;
+ case MO_32:
+ ret = x86_ldl_code(env, s);
+ break;
+#ifdef TARGET_X86_64
+ case MO_64:
+ ret = x86_ldq_code(env, s);
+ break;
+#endif
+ default:
+ g_assert_not_reached();
+ }
+ return ret;
+}
+
+static inline uint32_t insn_get(CPUX86State *env, DisasContext *s, MemOp ot)
+{
+ uint32_t ret;
+
+ switch (ot) {
+ case MO_8:
+ ret = x86_ldub_code(env, s);
+ break;
+ case MO_16:
+ ret = x86_lduw_code(env, s);
+ break;
+ case MO_32:
+#ifdef TARGET_X86_64
+ case MO_64:
+#endif
+ ret = x86_ldl_code(env, s);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return ret;
+}
+
+static target_long insn_get_signed(CPUX86State *env, DisasContext *s, MemOp ot)
+{
+ target_long ret;
+
+ switch (ot) {
+ case MO_8:
+ ret = (int8_t) x86_ldub_code(env, s);
+ break;
+ case MO_16:
+ ret = (int16_t) x86_lduw_code(env, s);
+ break;
+ case MO_32:
+ ret = (int32_t) x86_ldl_code(env, s);
+ break;
+#ifdef TARGET_X86_64
+ case MO_64:
+ ret = x86_ldq_code(env, s);
+ break;
+#endif
+ default:
+ g_assert_not_reached();
+ }
+ return ret;
+}
+
static uint8_t get_modrm(DisasContext *s, CPUX86State *env)
{
if (!s->has_modrm) {
@@ -1883,6 +2007,130 @@ static void decode_root(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui
*entry = opcodes_root[*b];
}
+/* Decompose an address. */
+static AddressParts decode_modrm_address(CPUX86State *env, DisasContext *s,
+ int modrm, bool is_vsib)
+{
+ int def_seg, base, index, scale, mod, rm;
+ target_long disp;
+ bool havesib;
+
+ def_seg = R_DS;
+ index = -1;
+ scale = 0;
+ disp = 0;
+
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+ base = rm | REX_B(s);
+
+ if (mod == 3) {
+ /* Normally filtered out earlier, but including this path
+ simplifies multi-byte nop, as well as bndcl, bndcu, bndcn. */
+ goto done;
+ }
+
+ switch (s->aflag) {
+ case MO_64:
+ case MO_32:
+ havesib = 0;
+ if (rm == 4) {
+ int code = x86_ldub_code(env, s);
+ scale = (code >> 6) & 3;
+ index = ((code >> 3) & 7) | REX_X(s);
+ if (index == 4 && !is_vsib) {
+ index = -1; /* no index */
+ }
+ base = (code & 7) | REX_B(s);
+ havesib = 1;
+ }
+
+ switch (mod) {
+ case 0:
+ if ((base & 7) == 5) {
+ base = -1;
+ disp = (int32_t)x86_ldl_code(env, s);
+ if (CODE64(s) && !havesib) {
+ base = -2;
+ disp += s->pc + s->rip_offset;
+ }
+ }
+ break;
+ case 1:
+ disp = (int8_t)x86_ldub_code(env, s);
+ break;
+ default:
+ case 2:
+ disp = (int32_t)x86_ldl_code(env, s);
+ break;
+ }
+
+ /* For correct popl handling with esp. */
+ if (base == R_ESP && s->popl_esp_hack) {
+ disp += s->popl_esp_hack;
+ }
+ if (base == R_EBP || base == R_ESP) {
+ def_seg = R_SS;
+ }
+ break;
+
+ case MO_16:
+ if (mod == 0) {
+ if (rm == 6) {
+ base = -1;
+ disp = x86_lduw_code(env, s);
+ break;
+ }
+ } else if (mod == 1) {
+ disp = (int8_t)x86_ldub_code(env, s);
+ } else {
+ disp = (int16_t)x86_lduw_code(env, s);
+ }
+
+ switch (rm) {
+ case 0:
+ base = R_EBX;
+ index = R_ESI;
+ break;
+ case 1:
+ base = R_EBX;
+ index = R_EDI;
+ break;
+ case 2:
+ base = R_EBP;
+ index = R_ESI;
+ def_seg = R_SS;
+ break;
+ case 3:
+ base = R_EBP;
+ index = R_EDI;
+ def_seg = R_SS;
+ break;
+ case 4:
+ base = R_ESI;
+ break;
+ case 5:
+ base = R_EDI;
+ break;
+ case 6:
+ base = R_EBP;
+ def_seg = R_SS;
+ break;
+ default:
+ case 7:
+ base = R_EBX;
+ break;
+ }
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ done:
+ return (AddressParts){ def_seg, base, index, scale, disp };
+}
+
static int decode_modrm(DisasContext *s, CPUX86State *env,
X86DecodedInsn *decode, X86DecodedOp *op)
{
@@ -1895,8 +2143,8 @@ static int decode_modrm(DisasContext *s, CPUX86State *env,
} else {
op->has_ea = true;
op->n = -1;
- decode->mem = gen_lea_modrm_0(env, s, modrm,
- decode->e.vex_class == 12);
+ decode->mem = decode_modrm_address(env, s, get_modrm(s, env),
+ decode->e.vex_class == 12);
}
return modrm;
}
@@ -2516,6 +2764,23 @@ illegal:
return false;
}
+static void dump_unknown_opcode(CPUX86State *env, DisasContext *s)
+{
+ if (qemu_loglevel_mask(LOG_UNIMP)) {
+ FILE *logfile = qemu_log_trylock();
+ if (logfile) {
+ target_ulong pc = s->base.pc_next, end = s->pc;
+
+ fprintf(logfile, "ILLOPC: " TARGET_FMT_lx ":", pc);
+ for (; pc < end; ++pc) {
+ fprintf(logfile, " %02x", translator_ldub(env, &s->base, pc));
+ }
+ fprintf(logfile, "\n");
+ qemu_log_unlock(logfile);
+ }
+ }
+}
+
/*
* Convert one instruction. s->base.is_jmp is set if the translation must
* be stopped.
@@ -2902,5 +3167,11 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
gen_illegal_opcode(s);
return;
unknown_op:
- gen_unknown_opcode(env, s);
+ /*
+ * Similarly, except that the assumption here is that we don't decode
+ * the instruction at all -- either a missing opcode, an unimplemented
+ * feature, or just a bogus instruction stream.
+ */
+ gen_illegal_opcode(s);
+ dump_unknown_opcode(env, s);
}
--
2.52.0
next prev parent reply other threads:[~2025-12-10 13:18 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-10 13:16 [PATCH 00/18] First round of target/i386/tcg patches for QEMU 11.0 Paolo Bonzini
2025-12-10 13:16 ` [PATCH 01/18] target/i386/tcg: fix check for invalid VSIB instruction Paolo Bonzini
2025-12-11 15:47 ` Richard Henderson
2025-12-11 20:28 ` Paolo Bonzini
2025-12-11 22:22 ` Richard Henderson
2025-12-12 2:06 ` Paolo Bonzini
2025-12-12 14:37 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 02/18] target/i386/tcg: ignore V3 in 32-bit mode Paolo Bonzini
2025-12-11 15:52 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 03/18] target/i386/tcg: update cc_op after PUSHF Paolo Bonzini
2025-12-11 15:55 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 04/18] target/i386/tcg: mark more instructions that are invalid in 64-bit mode Paolo Bonzini
2025-12-11 15:59 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 05/18] target/i386/tcg: do not compute all flags for SAHF Paolo Bonzini
2025-12-11 16:03 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 06/18] target/i386/tcg: remove do_decode_0F Paolo Bonzini
2025-12-11 16:03 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 07/18] target/i386/tcg: move and expand misplaced comment Paolo Bonzini
2025-12-11 16:04 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 08/18] target/i386/tcg: simplify effective address calculation Paolo Bonzini
2025-12-11 16:15 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 09/18] target/i386/tcg: unnest switch statements in disas_insn_x87 Paolo Bonzini
2025-12-11 16:20 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 10/18] target/i386/tcg: move fcom/fcomp differentiation to gen_helper_fp_arith_ST0_FT0 Paolo Bonzini
2025-12-11 16:21 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 11/18] target/i386/tcg: reuse gen_helper_fp_arith_ST0_FT0 for fcom STn and fcomp STn Paolo Bonzini
2025-12-11 16:24 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 12/18] target/i386/tcg: reuse gen_helper_fp_arith_ST0_FT0 for undocumented fcom/fcomp variants Paolo Bonzini
2025-12-11 16:26 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 13/18] target/i386/tcg: unify more pop/no-pop x87 instructions Paolo Bonzini
2025-12-10 13:16 ` [PATCH 14/18] target/i386/tcg: kill tmp1_i64 Paolo Bonzini
2025-12-11 16:28 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 15/18] target/i386/tcg: kill tmp2_i32 Paolo Bonzini
2025-12-11 16:29 ` Richard Henderson
2025-12-10 13:16 ` [PATCH 16/18] target/i386/tcg: commonize code to compute SF/ZF/PF Paolo Bonzini
2025-12-11 18:46 ` Richard Henderson
2025-12-12 15:45 ` Paolo Bonzini
2025-12-10 13:16 ` [PATCH 17/18] target/i386/tcg: add a CCOp for SBB x,x Paolo Bonzini
2025-12-11 19:11 ` Richard Henderson
2025-12-12 17:49 ` Paolo Bonzini
2025-12-10 13:16 ` Paolo Bonzini [this message]
2025-12-11 19:29 ` [PATCH 18/18] target/i386/tcg: move fetch code out of translate.c Richard Henderson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251210131653.852163-19-pbonzini@redhat.com \
--to=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).