diff options
Diffstat (limited to 'tcg')
| -rw-r--r-- | tcg/README | 8 | ||||
| -rw-r--r-- | tcg/aarch64/tcg-target.h | 1 | ||||
| -rw-r--r-- | tcg/aarch64/tcg-target.inc.c | 22 | ||||
| -rw-r--r-- | tcg/arm/tcg-target.h | 1 | ||||
| -rw-r--r-- | tcg/arm/tcg-target.inc.c | 54 | ||||
| -rw-r--r-- | tcg/i386/tcg-target.h | 1 | ||||
| -rw-r--r-- | tcg/i386/tcg-target.inc.c | 24 | ||||
| -rw-r--r-- | tcg/ia64/tcg-target.h | 1 | ||||
| -rw-r--r-- | tcg/mips/tcg-target.h | 1 | ||||
| -rw-r--r-- | tcg/mips/tcg-target.inc.c | 13 | ||||
| -rw-r--r-- | tcg/ppc/tcg-target.h | 1 | ||||
| -rw-r--r-- | tcg/ppc/tcg-target.inc.c | 7 | ||||
| -rw-r--r-- | tcg/s390/tcg-target.h | 1 | ||||
| -rw-r--r-- | tcg/s390/tcg-target.inc.c | 24 | ||||
| -rw-r--r-- | tcg/sparc/tcg-target.h | 1 | ||||
| -rw-r--r-- | tcg/sparc/tcg-target.inc.c | 11 | ||||
| -rw-r--r-- | tcg/tcg-op.c | 12 | ||||
| -rw-r--r-- | tcg/tcg-op.h | 11 | ||||
| -rw-r--r-- | tcg/tcg-opc.h | 1 | ||||
| -rw-r--r-- | tcg/tcg-runtime.h | 2 | ||||
| -rw-r--r-- | tcg/tcg.c | 5 | ||||
| -rw-r--r-- | tcg/tcg.h | 1 | ||||
| -rw-r--r-- | tcg/tci/tcg-target.h | 1 |
23 files changed, 178 insertions, 26 deletions
diff --git a/tcg/README b/tcg/README index a9858c2f74..bf49e8242b 100644 --- a/tcg/README +++ b/tcg/README @@ -477,6 +477,14 @@ current TB was linked to this TB. Otherwise execute the next instructions. Only indices 0 and 1 are valid and tcg_gen_goto_tb may be issued at most once with each slot index per TB. +* lookup_and_goto_ptr tb_addr + +Look up a TB address ('tb_addr') and jump to it if valid. If not valid, +jump to the TCG epilogue to go back to the exec loop. + +This operation is optional. If the TCG backend does not implement the +goto_ptr opcode, emitting this op is equivalent to emitting exit_tb(0). + * qemu_ld_i32/i64 t0, t1, flags, memidx * qemu_st_i32/i64 t0, t1, flags, memidx diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index 1a5ea23844..55a46ac825 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -77,6 +77,7 @@ typedef enum { #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_extrl_i64_i32 0 #define TCG_TARGET_HAS_extrh_i64_i32 0 +#define TCG_TARGET_HAS_goto_ptr 1 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 diff --git a/tcg/aarch64/tcg-target.inc.c b/tcg/aarch64/tcg-target.inc.c index 290de6dae6..5f185458f1 100644 --- a/tcg/aarch64/tcg-target.inc.c +++ b/tcg/aarch64/tcg-target.inc.c @@ -1357,8 +1357,13 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_exit_tb: - tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0); - tcg_out_goto(s, tb_ret_addr); + /* Reuse the zeroing that exists for goto_ptr. */ + if (a0 == 0) { + tcg_out_goto(s, s->code_gen_epilogue); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0); + tcg_out_goto(s, tb_ret_addr); + } break; case INDEX_op_goto_tb: @@ -1374,6 +1379,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, s->tb_jmp_reset_offset[a0] = tcg_current_code_size(s); break; + case INDEX_op_goto_ptr: + tcg_out_insn(s, 3207, BR, a0); + break; + case INDEX_op_br: tcg_out_goto_label(s, arg_label(a0)); break; @@ -1735,6 +1744,7 @@ static const TCGTargetOpDef aarch64_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_br, { } }, + { INDEX_op_goto_ptr, { "r" } }, { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, @@ -1942,6 +1952,14 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); tcg_out_insn(s, 3207, BR, tcg_target_call_iarg_regs[1]); + /* + * Return path for goto_ptr. Set return value to 0, a-la exit_tb, + * and fall through to the rest of the epilogue. + */ + s->code_gen_epilogue = s->code_ptr; + tcg_out_movi(s, TCG_TYPE_REG, TCG_REG_X0, 0); + + /* TB epilogue */ tb_ret_addr = s->code_ptr; /* Remove TCG locals stack space. */ diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index 75ea247bc4..5ef1086710 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -123,6 +123,7 @@ extern bool use_idiv_instructions; #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_div_i32 use_idiv_instructions #define TCG_TARGET_HAS_rem_i32 0 +#define TCG_TARGET_HAS_goto_ptr 1 enum { TCG_AREG0 = TCG_REG_R6, diff --git a/tcg/arm/tcg-target.inc.c b/tcg/arm/tcg-target.inc.c index e75a6d4943..9f5cb66718 100644 --- a/tcg/arm/tcg-target.inc.c +++ b/tcg/arm/tcg-target.inc.c @@ -329,11 +329,6 @@ static const uint8_t tcg_cond_to_arm_cond[] = { [TCG_COND_GTU] = COND_HI, }; -static inline void tcg_out_bx(TCGContext *s, int cond, int rn) -{ - tcg_out32(s, (cond << 28) | 0x012fff10 | rn); -} - static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset) { tcg_out32(s, (cond << 28) | 0x0a000000 | @@ -402,6 +397,18 @@ static inline void tcg_out_mov_reg(TCGContext *s, int cond, int rd, int rm) } } +static inline void tcg_out_bx(TCGContext *s, int cond, TCGReg rn) +{ + /* Unless the C portion of QEMU is compiled as thumb, we don't + actually need true BX semantics; merely a branch to an address + held in a register. */ + if (use_armv5t_instructions) { + tcg_out32(s, (cond << 28) | 0x012fff10 | rn); + } else { + tcg_out_mov_reg(s, cond, TCG_REG_PC, rn); + } +} + static inline void tcg_out_dat_imm(TCGContext *s, int cond, int opc, int rd, int rn, int im) { @@ -977,7 +984,7 @@ static inline void tcg_out_st8(TCGContext *s, int cond, * with the code buffer limited to 16MB we wouldn't need the long case. * But we also use it for the tail-call to the qemu_ld/st helpers, which does. */ -static inline void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr) +static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr) { intptr_t addri = (intptr_t)addr; ptrdiff_t disp = tcg_pcrel_diff(s, addr); @@ -987,15 +994,9 @@ static inline void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr) return; } + assert(use_armv5t_instructions || (addri & 1) == 0); tcg_out_movi32(s, cond, TCG_REG_TMP, addri); - if (use_armv5t_instructions) { - tcg_out_bx(s, cond, TCG_REG_TMP); - } else { - if (addri & 1) { - tcg_abort(); - } - tcg_out_mov_reg(s, cond, TCG_REG_PC, TCG_REG_TMP); - } + tcg_out_bx(s, cond, TCG_REG_TMP); } /* The call case is mostly used for helpers - so it's not unreasonable @@ -1654,8 +1655,14 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_exit_tb: - tcg_out_movi32(s, COND_AL, TCG_REG_R0, args[0]); - tcg_out_goto(s, COND_AL, tb_ret_addr); + /* Reuse the zeroing that exists for goto_ptr. */ + a0 = args[0]; + if (a0 == 0) { + tcg_out_goto(s, COND_AL, s->code_gen_epilogue); + } else { + tcg_out_movi32(s, COND_AL, TCG_REG_R0, args[0]); + tcg_out_goto(s, COND_AL, tb_ret_addr); + } break; case INDEX_op_goto_tb: if (s->tb_jmp_insn_offset) { @@ -1670,6 +1677,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, } s->tb_jmp_reset_offset[args[0]] = tcg_current_code_size(s); break; + case INDEX_op_goto_ptr: + tcg_out_bx(s, COND_AL, args[0]); + break; case INDEX_op_br: tcg_out_goto_label(s, COND_AL, arg_label(args[0])); break; @@ -1960,6 +1970,7 @@ static const TCGTargetOpDef arm_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_br, { } }, + { INDEX_op_goto_ptr, { "r" } }, { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, @@ -2135,9 +2146,16 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); tcg_out_bx(s, COND_AL, tcg_target_call_iarg_regs[1]); - tb_ret_addr = s->code_ptr; - /* Epilogue. We branch here via tb_ret_addr. */ + /* + * Return path for goto_ptr. Set return value to 0, a-la exit_tb, + * and fall through to the rest of the epilogue. + */ + s->code_gen_epilogue = s->code_ptr; + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, 0); + + /* TB epilogue */ + tb_ret_addr = s->code_ptr; tcg_out_dat_rI(s, COND_AL, ARITH_ADD, TCG_REG_CALL_STACK, TCG_REG_CALL_STACK, stack_addend, 1); diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 4275787db9..73a15f7e80 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -107,6 +107,7 @@ extern bool have_popcnt; #define TCG_TARGET_HAS_muls2_i32 1 #define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 +#define TCG_TARGET_HAS_goto_ptr 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extrl_i64_i32 0 diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c index 5918008296..01e3b4e95c 100644 --- a/tcg/i386/tcg-target.inc.c +++ b/tcg/i386/tcg-target.inc.c @@ -1882,8 +1882,13 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_exit_tb: - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, a0); - tcg_out_jmp(s, tb_ret_addr); + /* Reuse the zeroing that exists for goto_ptr. */ + if (a0 == 0) { + tcg_out_jmp(s, s->code_gen_epilogue); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, a0); + tcg_out_jmp(s, tb_ret_addr); + } break; case INDEX_op_goto_tb: if (s->tb_jmp_insn_offset) { @@ -1906,6 +1911,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, } s->tb_jmp_reset_offset[a0] = tcg_current_code_size(s); break; + case INDEX_op_goto_ptr: + /* jmp to the given host address (could be epilogue) */ + tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, a0); + break; case INDEX_op_br: tcg_out_jxx(s, JCC_JMP, arg_label(a0), 0); break; @@ -2277,6 +2286,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) { + static const TCGTargetOpDef r = { .args_ct_str = { "r" } }; static const TCGTargetOpDef ri_r = { .args_ct_str = { "ri", "r" } }; static const TCGTargetOpDef re_r = { .args_ct_str = { "re", "r" } }; static const TCGTargetOpDef qi_r = { .args_ct_str = { "qi", "r" } }; @@ -2299,6 +2309,9 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) = { .args_ct_str = { "L", "L", "L", "L" } }; switch (op) { + case INDEX_op_goto_ptr: + return &r; + case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i32: @@ -2567,6 +2580,13 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[1]); #endif + /* + * Return path for goto_ptr. Set return value to 0, a-la exit_tb, + * and fall through to the rest of the epilogue. + */ + s->code_gen_epilogue = s->code_ptr; + tcg_out_movi(s, TCG_TYPE_REG, TCG_REG_EAX, 0); + /* TB epilogue */ tb_ret_addr = s->code_ptr; diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h index 42aea03a8b..901bb7575d 100644 --- a/tcg/ia64/tcg-target.h +++ b/tcg/ia64/tcg-target.h @@ -173,6 +173,7 @@ typedef enum { #define TCG_TARGET_HAS_mulsh_i64 0 #define TCG_TARGET_HAS_extrl_i64_i32 0 #define TCG_TARGET_HAS_extrh_i64_i32 0 +#define TCG_TARGET_HAS_goto_ptr 0 #define TCG_TARGET_deposit_i32_valid(ofs, len) ((len) <= 16) #define TCG_TARGET_deposit_i64_valid(ofs, len) ((len) <= 16) diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index f46d64a3a7..d75cb63ed3 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -130,6 +130,7 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_muluh_i32 1 #define TCG_TARGET_HAS_mulsh_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 +#define TCG_TARGET_HAS_goto_ptr 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 diff --git a/tcg/mips/tcg-target.inc.c b/tcg/mips/tcg-target.inc.c index 2a7e1c7f5b..8cff9a6bf9 100644 --- a/tcg/mips/tcg-target.inc.c +++ b/tcg/mips/tcg-target.inc.c @@ -1747,6 +1747,11 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_nop(s); s->tb_jmp_reset_offset[a0] = tcg_current_code_size(s); break; + case INDEX_op_goto_ptr: + /* jmp to the given host address (could be epilogue) */ + tcg_out_opc_reg(s, OPC_JR, 0, a0, 0); + tcg_out_nop(s); + break; case INDEX_op_br: tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, arg_label(a0)); @@ -2160,6 +2165,7 @@ static const TCGTargetOpDef mips_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_br, { } }, + { INDEX_op_goto_ptr, { "r" } }, { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, @@ -2451,6 +2457,13 @@ static void tcg_target_qemu_prologue(TCGContext *s) /* delay slot */ tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); + /* + * Return path for goto_ptr. Set return value to 0, a-la exit_tb, + * and fall through to the rest of the epilogue. + */ + s->code_gen_epilogue = s->code_ptr; + tcg_out_mov(s, TCG_TYPE_REG, TCG_REG_V0, TCG_REG_ZERO); + /* TB epilogue */ tb_ret_addr = s->code_ptr; for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index abd8b3d6cd..5f4a40a5b4 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -82,6 +82,7 @@ extern bool have_isa_3_00; #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_muluh_i32 1 #define TCG_TARGET_HAS_mulsh_i32 1 +#define TCG_TARGET_HAS_goto_ptr 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 diff --git a/tcg/ppc/tcg-target.inc.c b/tcg/ppc/tcg-target.inc.c index 64f67d2c77..8d50f18328 100644 --- a/tcg/ppc/tcg-target.inc.c +++ b/tcg/ppc/tcg-target.inc.c @@ -1932,6 +1932,7 @@ static void tcg_target_qemu_prologue(TCGContext *s) /* Epilogue */ tcg_debug_assert(tb_ret_addr == s->code_ptr); + s->code_gen_epilogue = tb_ret_addr; tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R0, TCG_REG_R1, FRAME_SIZE+LR_OFFSET); for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); ++i) { @@ -1986,6 +1987,11 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, #endif s->tb_jmp_reset_offset[args[0]] = tcg_current_code_size(s); break; + case INDEX_op_goto_ptr: + tcg_out32(s, MTSPR | RS(args[0]) | CTR); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R3, 0); + tcg_out32(s, BCCTR | BO_ALWAYS); + break; case INDEX_op_br: { TCGLabel *l = arg_label(args[0]); @@ -2555,6 +2561,7 @@ static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_br, { } }, + { INDEX_op_goto_ptr, { "r" } }, { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h index cbdd2a6275..957f0c0afe 100644 --- a/tcg/s390/tcg-target.h +++ b/tcg/s390/tcg-target.h @@ -92,6 +92,7 @@ extern uint64_t s390_facilities; #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_extrl_i64_i32 0 #define TCG_TARGET_HAS_extrh_i64_i32 0 +#define TCG_TARGET_HAS_goto_ptr 1 #define TCG_TARGET_HAS_div2_i64 1 #define TCG_TARGET_HAS_rot_i64 1 diff --git a/tcg/s390/tcg-target.inc.c b/tcg/s390/tcg-target.inc.c index a679280b92..5d7083e90c 100644 --- a/tcg/s390/tcg-target.inc.c +++ b/tcg/s390/tcg-target.inc.c @@ -1741,9 +1741,14 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_exit_tb: - /* return value */ - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, args[0]); - tgen_gotoi(s, S390_CC_ALWAYS, tb_ret_addr); + /* Reuse the zeroing that exists for goto_ptr. */ + a0 = args[0]; + if (a0 == 0) { + tgen_gotoi(s, S390_CC_ALWAYS, s->code_gen_epilogue); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, a0); + tgen_gotoi(s, S390_CC_ALWAYS, tb_ret_addr); + } break; case INDEX_op_goto_tb: @@ -1767,6 +1772,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, s->tb_jmp_reset_offset[args[0]] = tcg_current_code_size(s); break; + case INDEX_op_goto_ptr: + tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, args[0]); + break; + OP_32_64(ld8u): /* ??? LLC (RXY format) is only present with the extended-immediate facility, whereas LLGC is always present. */ @@ -2241,6 +2250,7 @@ static const TCGTargetOpDef s390_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_br, { } }, + { INDEX_op_goto_ptr, { "r" } }, { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, @@ -2439,6 +2449,14 @@ static void tcg_target_qemu_prologue(TCGContext *s) /* br %r3 (go to TB) */ tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, tcg_target_call_iarg_regs[1]); + /* + * Return path for goto_ptr. Set return value to 0, a-la exit_tb, + * and fall through to the rest of the epilogue. + */ + s->code_gen_epilogue = s->code_ptr; + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, 0); + + /* TB epilogue */ tb_ret_addr = s->code_ptr; /* lmg %r6,%r15,fs+48(%r15) (restore registers) */ diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index b8b74f96ff..854a0afd70 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -123,6 +123,7 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_muls2_i32 1 #define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 +#define TCG_TARGET_HAS_goto_ptr 1 #define TCG_TARGET_HAS_extrl_i64_i32 1 #define TCG_TARGET_HAS_extrh_i64_i32 1 diff --git a/tcg/sparc/tcg-target.inc.c b/tcg/sparc/tcg-target.inc.c index 3785d77f62..18afce2f87 100644 --- a/tcg/sparc/tcg-target.inc.c +++ b/tcg/sparc/tcg-target.inc.c @@ -1003,7 +1003,11 @@ static void tcg_target_qemu_prologue(TCGContext *s) /* delay slot */ tcg_out_nop(s); - /* No epilogue required. We issue ret + restore directly in the TB. */ + /* Epilogue for goto_ptr. */ + s->code_gen_epilogue = s->code_ptr; + tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN); + /* delay slot */ + tcg_out_movi_imm13(s, TCG_REG_O0, 0); #ifdef CONFIG_SOFTMMU build_trampolines(s); @@ -1288,6 +1292,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_nop(s); s->tb_jmp_reset_offset[a0] = tcg_current_code_size(s); break; + case INDEX_op_goto_ptr: + tcg_out_arithi(s, TCG_REG_G0, a0, 0, JMPL); + tcg_out_nop(s); + break; case INDEX_op_br: tcg_out_bpcc(s, COND_A, BPCC_PT, arg_label(a0)); tcg_out_nop(s); @@ -1513,6 +1521,7 @@ static const TCGTargetOpDef sparc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_br, { } }, + { INDEX_op_goto_ptr, { "r" } }, { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 6b1f41500c..87f673ef49 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2587,6 +2587,18 @@ void tcg_gen_goto_tb(unsigned idx) tcg_gen_op1i(INDEX_op_goto_tb, idx); } +void tcg_gen_lookup_and_goto_ptr(TCGv addr) +{ + if (TCG_TARGET_HAS_goto_ptr && !qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { + TCGv_ptr ptr = tcg_temp_new_ptr(); + gen_helper_lookup_tb_ptr(ptr, tcg_ctx.tcg_env, addr); + tcg_gen_op1i(INDEX_op_goto_ptr, GET_TCGV_PTR(ptr)); + tcg_temp_free_ptr(ptr); + } else { + tcg_gen_exit_tb(0); + } +} + static inline TCGMemOp tcg_canonicalize_memop(TCGMemOp op, bool is64, bool st) { /* Trigger the asserts within as early as possible. */ diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index c68e300a68..5d3278f243 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -796,6 +796,17 @@ static inline void tcg_gen_exit_tb(uintptr_t val) */ void tcg_gen_goto_tb(unsigned idx); +/** + * tcg_gen_lookup_and_goto_ptr() - look up a TB and jump to it if valid + * @addr: Guest address of the target TB + * + * If the TB is not valid, jump to the epilogue. + * + * This operation is optional. If the TCG backend does not implement goto_ptr, + * this op is equivalent to calling tcg_gen_exit_tb() with 0 as the argument. + */ +void tcg_gen_lookup_and_goto_ptr(TCGv addr); + #if TARGET_LONG_BITS == 32 #define tcg_temp_new() tcg_temp_new_i32() #define tcg_global_reg_new tcg_global_reg_new_i32 diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index f06f89405e..956fb1e9f3 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -193,6 +193,7 @@ DEF(insn_start, 0, 0, TLADDR_ARGS * TARGET_INSN_START_WORDS, TCG_OPF_NOT_PRESENT) DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_END) DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_END) +DEF(goto_ptr, 0, 1, 0, TCG_OPF_BB_END | IMPL(TCG_TARGET_HAS_goto_ptr)) DEF(qemu_ld_i32, 1, TLADDR_ARGS, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) diff --git a/tcg/tcg-runtime.h b/tcg/tcg-runtime.h index 114ea6fecf..c41d38a557 100644 --- a/tcg/tcg-runtime.h +++ b/tcg/tcg-runtime.h @@ -24,6 +24,8 @@ DEF_HELPER_FLAGS_1(clrsb_i64, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_1(ctpop_i32, TCG_CALL_NO_RWG_SE, i32, i32) DEF_HELPER_FLAGS_1(ctpop_i64, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_2(lookup_tb_ptr, TCG_CALL_NO_WG_SE, ptr, env, tl) + DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env) #ifdef CONFIG_SOFTMMU diff --git a/tcg/tcg.c b/tcg/tcg.c index cb898f1636..564292f54d 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -424,6 +424,11 @@ void tcg_prologue_init(TCGContext *s) qemu_log_unlock(); } #endif + + /* Assert that goto_ptr is implemented completely. */ + if (TCG_TARGET_HAS_goto_ptr) { + tcg_debug_assert(s->code_gen_epilogue != NULL); + } } void tcg_func_start(TCGContext *s) diff --git a/tcg/tcg.h b/tcg/tcg.h index 6c216bb73f..5ec48d1787 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -699,6 +699,7 @@ struct TCGContext { extension that allows arithmetic on void*. */ int code_gen_max_blocks; void *code_gen_prologue; + void *code_gen_epilogue; void *code_gen_buffer; size_t code_gen_buffer_size; void *code_gen_ptr; diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 838bf3a858..06963288dc 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -85,6 +85,7 @@ #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 +#define TCG_TARGET_HAS_goto_ptr 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extrl_i64_i32 0 |