tcg/loongarch64: Add direct jump support
Similar to the ARM64, LoongArch has PC-relative instructions such as PCADDU18I. These instructions can be used to support direct jump for LoongArch. Additionally, if instruction "B offset" can cover the target address(target is within ±128MB range), a single "B offset" plus a nop will be used by "tb_target_set_jump_target". Signed-off-by: Qi Hu <huqi@loongson.cn> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: WANG Xuerui <git@xen0n.name> Message-Id: <20221015092754.91971-1-huqi@loongson.cn> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
0585105c80
commit
f072a1ae7f
@ -1031,6 +1031,36 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* LoongArch uses `andi zero, zero, 0` as NOP. */
|
||||||
|
#define NOP OPC_ANDI
|
||||||
|
static void tcg_out_nop(TCGContext *s)
|
||||||
|
{
|
||||||
|
tcg_out32(s, NOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx,
|
||||||
|
uintptr_t jmp_rw, uintptr_t addr)
|
||||||
|
{
|
||||||
|
tcg_insn_unit i1, i2;
|
||||||
|
ptrdiff_t upper, lower;
|
||||||
|
ptrdiff_t offset = (ptrdiff_t)(addr - jmp_rx) >> 2;
|
||||||
|
|
||||||
|
if (offset == sextreg(offset, 0, 26)) {
|
||||||
|
i1 = encode_sd10k16_insn(OPC_B, offset);
|
||||||
|
i2 = NOP;
|
||||||
|
} else {
|
||||||
|
tcg_debug_assert(offset == sextreg(offset, 0, 36));
|
||||||
|
lower = (int16_t)offset;
|
||||||
|
upper = (offset - lower) >> 16;
|
||||||
|
|
||||||
|
i1 = encode_dsj20_insn(OPC_PCADDU18I, TCG_REG_TMP0, upper);
|
||||||
|
i2 = encode_djsk16_insn(OPC_JIRL, TCG_REG_ZERO, TCG_REG_TMP0, lower);
|
||||||
|
}
|
||||||
|
uint64_t pair = ((uint64_t)i2 << 32) | i1;
|
||||||
|
qatomic_set((uint64_t *)jmp_rw, pair);
|
||||||
|
flush_idcache_range(jmp_rx, jmp_rw, 8);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Entry-points
|
* Entry-points
|
||||||
*/
|
*/
|
||||||
@ -1058,10 +1088,20 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case INDEX_op_goto_tb:
|
case INDEX_op_goto_tb:
|
||||||
assert(s->tb_jmp_insn_offset == 0);
|
tcg_debug_assert(s->tb_jmp_insn_offset != NULL);
|
||||||
/* indirect jump method */
|
/*
|
||||||
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO,
|
* Ensure that patch area is 8-byte aligned so that an
|
||||||
(uintptr_t)(s->tb_jmp_target_addr + a0));
|
* atomic write can be used to patch the target address.
|
||||||
|
*/
|
||||||
|
if ((uintptr_t)s->code_ptr & 7) {
|
||||||
|
tcg_out_nop(s);
|
||||||
|
}
|
||||||
|
s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
|
||||||
|
/*
|
||||||
|
* actual branch destination will be patched by
|
||||||
|
* tb_target_set_jmp_target later
|
||||||
|
*/
|
||||||
|
tcg_out_opc_pcaddu18i(s, TCG_REG_TMP0, 0);
|
||||||
tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_TMP0, 0);
|
tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_TMP0, 0);
|
||||||
set_jmp_reset_offset(s, a0);
|
set_jmp_reset_offset(s, a0);
|
||||||
break;
|
break;
|
||||||
|
@ -42,7 +42,11 @@
|
|||||||
|
|
||||||
#define TCG_TARGET_INSN_UNIT_SIZE 4
|
#define TCG_TARGET_INSN_UNIT_SIZE 4
|
||||||
#define TCG_TARGET_NB_REGS 32
|
#define TCG_TARGET_NB_REGS 32
|
||||||
#define MAX_CODE_GEN_BUFFER_SIZE SIZE_MAX
|
/*
|
||||||
|
* PCADDU18I + JIRL sequence can give 20 + 16 + 2 = 38 bits
|
||||||
|
* signed offset, which is +/- 128 GiB.
|
||||||
|
*/
|
||||||
|
#define MAX_CODE_GEN_BUFFER_SIZE (128 * GiB)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TCG_REG_ZERO,
|
TCG_REG_ZERO,
|
||||||
@ -123,7 +127,7 @@ typedef enum {
|
|||||||
#define TCG_TARGET_HAS_clz_i32 1
|
#define TCG_TARGET_HAS_clz_i32 1
|
||||||
#define TCG_TARGET_HAS_ctz_i32 1
|
#define TCG_TARGET_HAS_ctz_i32 1
|
||||||
#define TCG_TARGET_HAS_ctpop_i32 0
|
#define TCG_TARGET_HAS_ctpop_i32 0
|
||||||
#define TCG_TARGET_HAS_direct_jump 0
|
#define TCG_TARGET_HAS_direct_jump 1
|
||||||
#define TCG_TARGET_HAS_brcond2 0
|
#define TCG_TARGET_HAS_brcond2 0
|
||||||
#define TCG_TARGET_HAS_setcond2 0
|
#define TCG_TARGET_HAS_setcond2 0
|
||||||
#define TCG_TARGET_HAS_qemu_st8_i32 0
|
#define TCG_TARGET_HAS_qemu_st8_i32 0
|
||||||
@ -166,7 +170,6 @@ typedef enum {
|
|||||||
#define TCG_TARGET_HAS_muluh_i64 1
|
#define TCG_TARGET_HAS_muluh_i64 1
|
||||||
#define TCG_TARGET_HAS_mulsh_i64 1
|
#define TCG_TARGET_HAS_mulsh_i64 1
|
||||||
|
|
||||||
/* not defined -- call should be eliminated at compile time */
|
|
||||||
void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
|
void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
|
||||||
|
|
||||||
#define TCG_TARGET_DEFAULT_MO (0)
|
#define TCG_TARGET_DEFAULT_MO (0)
|
||||||
|
Loading…
Reference in New Issue
Block a user