Use comparisons vs memory, short branches, and
an indirect memory jump.
Signed-off-by: Richard Henderson <[email protected]>
---
tcg/x86_64/tcg-target-con-set.h | 1 +
tcg/tcg.c | 1 +
tcg/x86_64/tcg-target.c.inc | 63 ++++++++++++++++++++++++++++++++-
3 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/tcg/x86_64/tcg-target-con-set.h b/tcg/x86_64/tcg-target-con-set.h
index 5af8c1cb2cd..f3359ae5bce 100644
--- a/tcg/x86_64/tcg-target-con-set.h
+++ b/tcg/x86_64/tcg-target-con-set.h
@@ -26,6 +26,7 @@ C_O0_I2(x, r)
C_O0_I3(L, L, L)
C_O0_I3(s, L, L)
C_O0_I4(L, L, L, L)
+C_O0_I4(r, r, re, re)
C_O0_I4(r, r, ri, ri)
C_O1_I1(r, 0)
C_O1_I1(r, L)
diff --git a/tcg/tcg.c b/tcg/tcg.c
index a08e83f3954..2650119dedb 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -61,6 +61,7 @@
#ifdef CONFIG_USER_ONLY
#include "user/guest-base.h"
#endif
+#include "../accel/tcg/tb-hash.h"
/* Forward declarations for functions declared in tcg-target.c.inc and
used here. */
diff --git a/tcg/x86_64/tcg-target.c.inc b/tcg/x86_64/tcg-target.c.inc
index 08dec0dace8..7f510545b48 100644
--- a/tcg/x86_64/tcg-target.c.inc
+++ b/tcg/x86_64/tcg-target.c.inc
@@ -1531,6 +1531,25 @@ static int tcg_out_cmp(TCGContext *s, TCGCond cond,
TCGArg arg1,
return jz;
}
+static void tgen_cmp_mem_reg(TCGContext *s, int rexw, TCGReg reg,
+ TCGReg base, intptr_t ofs)
+{
+ tcg_out_modrm_offset(s, OPC_CMP_GvEv | rexw, reg, base, ofs);
+}
+
+static void tgen_cmp_mem_imm(TCGContext *s, int rexw, int64_t imm,
+ TCGReg base, intptr_t ofs)
+{
+ if (imm == (int8_t)imm) {
+ tcg_out_modrm_offset(s, OPC_ARITH_EvIb | rexw, ARITH_CMP, base, ofs);
+ tcg_out8(s, imm);
+ } else {
+ tcg_debug_assert(imm == (int32_t)imm);
+ tcg_out_modrm_offset(s, OPC_ARITH_EvIz | rexw, ARITH_CMP, base, ofs);
+ tcg_out32(s, imm);
+ }
+}
+
static void tcg_out_brcond(TCGContext *s, int rexw, TCGCond cond,
TCGArg arg1, TCGArg arg2, int const_arg2,
TCGLabel *label, bool small)
@@ -3344,8 +3363,50 @@ static const TCGOutOpLea outop_lea = {
.out = tgen_lea,
};
+static void tgen_goto_jc(TCGContext *s, TCGReg ptr, TCGReg pc,
+ TCGArg cs, bool const_cs, TCGArg fl, bool const_fl,
+ TCGLabel *label)
+{
+ /* ptr is CPUJumpCache */
+
+ /* Validate pc match */
+ tgen_cmp_mem_reg(s, P_REXW, pc, ptr, offsetof(CPUJumpCache, array[0].pc));
+ tcg_out_jxx(s, JCC_JNE, label, true);
+
+ /* Load and validate tb non-null */
+ tcg_out_ld(s, TCG_TYPE_PTR, ptr, ptr, offsetof(CPUJumpCache, array[0].tb));
+ tcg_out_brcond(s, P_REXW, TCG_COND_EQ, ptr, 0, true, label, true);
+
+ /* ptr is now TranslationBlock */
+
+ /* Validate cs_base match */
+ if (const_cs) {
+ tgen_cmp_mem_imm(s, P_REXW, cs, ptr,
+ offsetof(TranslationBlock, cs_base));
+ } else {
+ tgen_cmp_mem_reg(s, P_REXW, cs, ptr,
+ offsetof(TranslationBlock, cs_base));
+ }
+ tcg_out_jxx(s, JCC_JNE, label, true);
+
+ /* Validate flags:cflags match */
+ if (const_fl) {
+ tgen_cmp_mem_imm(s, P_REXW, fl, ptr,
+ offsetof(TranslationBlock, flags));
+ } else {
+ tgen_cmp_mem_reg(s, P_REXW, fl, ptr,
+ offsetof(TranslationBlock, flags));
+ }
+ tcg_out_jxx(s, JCC_JNE, label, true);
+
+ /* Jump to tb */
+ tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev,
+ ptr, offsetof(TranslationBlock, tc.ptr));
+}
+
static const TCGOutOpGotoJC outop_goto_jc = {
- .base.static_constraint = C_NotImplemented,
+ .base.static_constraint = C_O0_I4(r, r, re, re),
+ .out = tgen_goto_jc,
};
static int const umin_insn[4] = {
--
2.53.0