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


Reply via email to