sh2 drc: drc exit, block linking and branch handling revised

This commit is contained in:
kub 2019-09-28 16:39:26 +02:00
parent 36614252d9
commit 06bc3c0693
5 changed files with 462 additions and 246 deletions

View file

@ -631,8 +631,8 @@ static void emith_pool_commit(int jumpover)
static inline void emith_pool_check(void)
{
// check if pool must be committed
if (literal_iindex > MAX_HOST_LITERALS-4 ||
(u8 *)tcache_ptr - (u8 *)literal_insn[0] > 0xe00)
if (literal_iindex > MAX_HOST_LITERALS-4 || (literal_pindex &&
(u8 *)tcache_ptr - (u8 *)literal_insn[0] > 0xe00))
// pool full, or displacement is approaching the limit
emith_pool_commit(1);
}
@ -889,11 +889,19 @@ static inline void emith_pool_adjust(int pool_index, int move_offs)
#define emith_tst_r_imm_c(cond, r, imm) \
emith_top_imm(cond, A_OP_TST, r, imm)
#define emith_move_r_imm_s8(r, imm) do { \
#define emith_move_r_imm_s8_patchable(r, imm) do { \
emith_flush(); \
if ((s8)(imm) < 0) \
EOP_MVN_IMM(r, 0, ((u8)(imm) ^ 0xff)); \
EOP_MVN_IMM(r, 0, (u8)~(imm)); \
else \
EOP_MOV_IMM(r, 0, (u8)imm); \
EOP_MOV_IMM(r, 0, (u8)(imm)); \
} while (0)
#define emith_move_r_imm_s8_patch(ptr, imm) do { \
u32 *ptr_ = (u32 *)ptr; u32 op_ = *ptr_ & 0xfe1ff000; \
if ((s8)(imm) < 0) \
EMIT_PTR(ptr_, op_ | (A_OP_MVN<<21) | (u8)~(imm));\
else \
EMIT_PTR(ptr_, op_ | (A_OP_MOV<<21) | (u8)(imm));\
} while (0)
#define emith_and_r_r_imm(d, s, imm) \
@ -1125,7 +1133,6 @@ static inline void emith_pool_adjust(int pool_index, int move_offs)
#define emith_jump_patchable(target) \
emith_jump(target)
#define emith_jump_patchable_size() 4
#define emith_jump_cond(cond, target) \
emith_xbranch(cond, target, 0)
@ -1135,18 +1142,19 @@ static inline void emith_pool_adjust(int pool_index, int move_offs)
emith_jump_cond(cond, target)
#define emith_jump_patch(ptr, target, pos) do { \
u32 *ptr_ = ptr; \
u32 *ptr_ = (u32 *)ptr; \
u32 val_ = (u32 *)(target) - ptr_ - 2; \
*ptr_ = (*ptr_ & 0xff000000) | (val_ & 0x00ffffff); \
if ((void *)(pos) != NULL) *(u8 **)(pos) = (u8 *)ptr; \
} while (0)
#define emith_jump_patch_inrange(ptr, target) !0
#define emith_jump_patch_size() 4
#define emith_jump_at(ptr, target) do { \
u32 val_ = (u32 *)(target) - (u32 *)(ptr) - 2; \
emith_flush(); \
EOP_C_B_PTR(ptr, A_COND_AL, 0, val_ & 0xffffff); \
} while (0)
#define emith_jump_at_size() 4
#define emith_jump_reg_c(cond, r) \
EOP_C_BX(cond, r)
@ -1187,8 +1195,8 @@ static inline void emith_pool_adjust(int pool_index, int move_offs)
#define emith_ret_to_ctx(offs) \
emith_ctx_write(LR, offs)
#define emith_add_r_ret_imm(r, imm) \
emith_add_r_r_ptr_imm(r, LR, imm)
#define emith_add_r_ret(r) \
emith_add_r_r_ptr(r, LR)
/* pushes r12 for eabi alignment */
#define emith_push_ret(r) do { \

View file

@ -447,6 +447,8 @@ enum { AM_IDX, AM_IDXPOST, AM_IDXREG, AM_IDXPRE };
#define emith_eor_r_r_r(d, s1, s2) \
emith_eor_r_r_r_lsl(d, s1, s2, 0)
#define emith_add_r_r_r_ptr(d, s1, s2) \
emith_add_r_r_r_lsl_ptr(d, s1, s2, 0)
#define emith_and_r_r_r(d, s1, s2) \
emith_and_r_r_r_lsl(d, s1, s2, 0)
@ -546,6 +548,20 @@ static void emith_move_imm64(int r, int wx, int64_t imm)
#define emith_move_r_imm_c(cond, r, imm) \
emith_move_r_imm(r, imm)
#define emith_move_r_imm_s8_patchable(r, imm) do { \
if ((s8)(imm) < 0) \
EMIT(A64_MOVN_IMM(r, ~(s8)(imm), 0)); \
else \
EMIT(A64_MOVZ_IMM(r, (s8)(imm), 0)); \
} while (0)
#define emith_move_r_imm_s8_patch(ptr, imm) do { \
u32 *ptr_ = (u32 *)ptr; \
int r_ = *ptr_ & 0x1f; \
if ((s8)(imm) < 0) \
EMIT_PTR(ptr_, A64_MOVN_IMM(r_, ~(s8)(imm), 0)); \
else \
EMIT_PTR(ptr_, A64_MOVZ_IMM(r_, (s8)(imm), 0)); \
} while (0)
// arithmetic, immediate
static void emith_arith_imm(int op, int wx, int rd, int rn, s32 imm)
@ -995,16 +1011,6 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
emith_move_r_imm(arg, imm)
// branching; NB: A64 B.cond has only +/- 1MB range
#define emith_bcond(ptr, patch, cond, target) do { \
u32 disp_ = (u8 *)target - (u8 *)ptr; \
if (disp_ >= 0xfff00000 || disp_ <= 0x000fffff) { /* can use near B.c */ \
EMIT_PTR(ptr, A64_BCOND(cond, disp_ & 0x001fffff)); \
if (patch) EMIT_PTR(ptr, A64_NOP); /* reserve space for far B */ \
} else { /* far branch if near branch isn't possible */ \
EMIT_PTR(ptr, A64_BCOND(emith_invert_cond(cond), 8)); \
EMIT_PTR(ptr, A64_B((disp_ - 4) & 0x0fffffff)); \
} \
} while (0)
#define emith_jump(target) do {\
u32 disp_ = (u8 *)target - (u8 *)tcache_ptr; \
@ -1013,30 +1019,37 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
#define emith_jump_patchable(target) \
emith_jump(target)
#define emith_jump_patchable_size() 4
#define emith_jump_cond(cond, target) \
emith_bcond(tcache_ptr, 0, cond, target)
#define emith_jump_cond(cond, target) do { \
u32 disp_ = (u8 *)target - (u8 *)tcache_ptr; \
EMIT(A64_BCOND(cond, disp_ & 0x001fffff)); \
} while (0)
#define emith_jump_cond_patchable(cond, target) \
emith_bcond(tcache_ptr, 1, cond, target)
emith_jump_cond(cond, target)
#define emith_jump_cond_inrange(target) \
!(((u8 *)target - (u8 *)tcache_ptr + 0x100000) >> 21)
#define emith_jump_patch(ptr, target, pos) do { \
u32 *ptr_ = (u32 *)ptr; \
u32 disp_ = (u8 *)(target) - (u8 *)(ptr_); \
int cond_ = ptr_[0] & 0xf; \
if ((ptr_[0] & 0xff000000) == 0x54000000) { /* B.cond */ \
if (ptr_[1] != A64_NOP) cond_ = emith_invert_cond(cond_); \
emith_bcond(ptr_, 1, cond_, target); \
} else if (ptr_[0] & 0x80000000) \
EMIT_PTR(ptr_, A64_BL((disp_) & 0x0fffffff)); \
else EMIT_PTR(ptr_, A64_B((disp_) & 0x0fffffff)); \
if ((void *)(pos) != NULL) *(u8 **)(pos) = (u8 *)ptr; \
u32 disp_ = (u8 *)target - (u8 *)ptr, mask_; \
if ((*ptr_ & 0xff000000) == 0x54000000) \
mask_ = 0xff00001f, disp_ <<= 5; /* B.cond, range 21 bit */ \
else mask_ = 0xfc000000; /* B[L], range 28 bit */ \
EMIT_PTR(ptr_, (*ptr_ & mask_) | ((disp_ >> 2) & ~mask_)); \
if ((void *)(pos) != NULL) *(u8 **)(pos) = (u8 *)(ptr_-1); \
} while (0)
#define emith_jump_patch_size() 8
#define emith_jump_patch_inrange(ptr, target) \
!(((u8 *)target - (u8 *)ptr + 0x100000) >> 21)
#define emith_jump_patch_size() 4
#define emith_jump_at(ptr, target) do { \
u32 disp_ = (u8 *)target - (u8 *)ptr; \
EMIT_PTR(ptr, A64_B(disp_ & 0x0fffffff)); \
} while (0)
#define emith_jump_at_size() 4
#define emith_jump_reg(r) \
EMIT(A64_BR(r))
@ -1079,8 +1092,8 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
#define emith_ret_to_ctx(offs) \
emith_ctx_write_ptr(LR, offs)
#define emith_add_r_ret_imm(r, imm) \
emith_add_r_r_ptr_imm(r, LR, imm)
#define emith_add_r_ret(r) \
emith_add_r_r_r_ptr(r, LR, r)
// NB: pushes r or r18 for SP hardware alignment
#define emith_push_ret(r) do { \

View file

@ -285,7 +285,7 @@ static int emith_b_isswap(u32 bop, u32 lop)
return bop;
else if (emith_is_b(bop) && emith_rd(lop) != emith_rs(bop))
if ((bop & 0xffff) != 0x7fff) // displacement overflow?
return (bop & 0xffff0000) | ((bop & 0xffff)+1);
return (bop & 0xffff0000) | ((bop+1) & 0x0000ffff);
return 0;
}
@ -332,14 +332,14 @@ static void *emith_branch(u32 op)
#define JMP_EMIT(cond, ptr) { \
u32 val_ = (u8 *)tcache_ptr - (u8 *)(ptr) - 4; \
EMIT_PTR(ptr, MIPS_BCONDZ(cond_m, cond_r, val_ & 0x0003ffff)); \
emith_flush(); /* NO delay slot handling across jump targets */ \
EMIT_PTR(ptr, MIPS_BCONDZ(cond_m, cond_r, val_ & 0x0003ffff)); \
}
#define JMP_EMIT_NC(ptr) { \
u32 val_ = (u8 *)tcache_ptr - (u8 *)(ptr) - 4; \
EMIT_PTR(ptr, MIPS_B(val_ & 0x0003ffff)); \
emith_flush(); \
EMIT_PTR(ptr, MIPS_B(val_ & 0x0003ffff)); \
}
#define EMITH_JMP_START(cond) { \
@ -645,6 +645,13 @@ static void emith_move_imm(int r, uintptr_t imm)
#define emith_move_r_imm_c(cond, r, imm) \
emith_move_r_imm(r, imm)
#define emith_move_r_imm_s8_patchable(r, imm) \
EMIT(MIPS_ADD_IMM(r, Z0, (s8)(imm)))
#define emith_move_r_imm_s8_patch(ptr, imm) do { \
u32 *ptr_ = (u32 *)ptr; \
while (*ptr_ >> 26 != OP_ADDIU) ptr_++; \
EMIT_PTR(ptr_, (*ptr_ & 0xffff0000) | (u16)(s8)(imm)); \
} while (0)
// arithmetic, immediate
static void emith_arith_imm(int op, int rd, int rs, u32 imm)
@ -1162,41 +1169,44 @@ static int emith_cond_check(int cond, int *r)
emith_branch(MIPS_J((uintptr_t)target & 0x0fffffff))
#define emith_jump_patchable(target) \
emith_jump(target)
#define emith_jump_patchable_size() 8 /* J+delayslot */
// NB: MIPS conditional branches have only +/- 128KB range
#define emith_jump_cond(cond, target) do { \
int r_, mcond_ = emith_cond_check(cond, &r_); \
u32 disp_ = (u8 *)target - (u8 *)tcache_ptr - 4; \
if (disp_ >= 0xfffe0000 || disp_ <= 0x0001ffff) { /* can use near B */ \
emith_branch(MIPS_BCONDZ(mcond_,r_,disp_ & 0x0003ffff)); \
} else { /* far branch if near branch isn't possible */ \
mcond_ = emith_invert_branch(mcond_); \
u8 *bp = emith_branch(MIPS_BCONDZ(mcond_, r_, 0)); \
emith_branch(MIPS_J((uintptr_t)target & 0x0fffffff)); \
EMIT_PTR(bp, MIPS_BCONDZ(mcond_, r_, (u8 *)tcache_ptr-bp-4)); \
} \
emith_branch(MIPS_BCONDZ(mcond_,r_,disp_ & 0x0003ffff)); \
} while (0)
#define emith_jump_cond_inrange(target) \
!(((u8 *)target - (u8 *)tcache_ptr + 0x20000) >> 18)
#define emith_jump_cond_patchable(cond, target) \
emith_jump_cond(cond, target)
#define emith_jump_cond_patchable(cond, target) do { \
int r_, mcond_ = emith_cond_check(cond, &r_); \
mcond_ = emith_invert_branch(mcond_); \
u8 *bp = emith_branch(MIPS_BCONDZ(mcond_, r_, 0));\
emith_branch(MIPS_J((uintptr_t)target & 0x0fffffff)); \
EMIT_PTR(bp, MIPS_BCONDZ(mcond_, r_, (u8 *)tcache_ptr-bp-4)); \
} while (0)
#define emith_jump_cond_inrange(target) \
((u8 *)target - (u8 *)tcache_ptr - 4 < 0x00020000U || \
(u8 *)target - (u8 *)tcache_ptr - 4 >= 0xfffe0010U) // mind cond_check
// NB: returns position of patch for cache maintenance
#define emith_jump_patch(ptr, target, pos) do { \
u32 *ptr_ = (u32 *)ptr-1; /* must skip condition check code */ \
while ((ptr_[0] & 0xf8000000) != OP_J << 26) ptr_ ++; \
EMIT_PTR(ptr_, MIPS_J((uintptr_t)target & 0x0fffffff)); \
u32 disp_, mask_; \
while (!emith_is_j(*ptr_) && !emith_is_b(*ptr_)) ptr_ ++; \
if (emith_is_b(*ptr_)) \
mask_ = 0xffff0000, disp_ = (u8 *)target - (u8 *)ptr_ - 4; \
else mask_ = 0xfc000000, disp_ = (uintptr_t)target; \
EMIT_PTR(ptr_, (*ptr_ & mask_) | ((disp_ >> 2) & ~mask_)); \
if ((void *)(pos) != NULL) *(u8 **)(pos) = (u8 *)(ptr_-1); \
} while (0)
#define emith_jump_patch_inrange(ptr, target) \
((u8 *)target - (u8 *)ptr - 4 < 0x00020000U || \
(u8 *)target - (u8 *)ptr - 4 >= 0xfffe0010U) // mind cond_check
#define emith_jump_patch_size() 4
#define emith_jump_at(ptr, target) do { \
u32 *ptr_ = (u32 *)ptr; \
EMIT_PTR(ptr_, MIPS_J((uintptr_t)target & 0x0fffffff)); \
EMIT_PTR(ptr_, MIPS_NOP); \
} while (0)
#define emith_jump_at_size() 8
#define emith_jump_reg(r) \
emith_branch(MIPS_JR(r))
#define emith_jump_reg_c(cond, r) \
@ -1232,8 +1242,8 @@ static int emith_cond_check(int cond, int *r)
#define emith_ret_to_ctx(offs) \
emith_ctx_write_ptr(LR, offs)
#define emith_add_r_ret_imm(r, imm) \
emith_add_r_r_ptr_imm(r, LR, imm)
#define emith_add_r_ret(r) \
emith_add_r_r_ptr(r, LR)
// NB: ABI SP alignment is 8 for compatibility with MIPS IV
#define emith_push_ret(r) do { \

View file

@ -371,8 +371,16 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
} \
} while (0)
#define emith_move_r_imm_s8(r, imm) \
emith_move_r_imm(r, (u32)(signed int)(signed char)(imm))
#define emith_move_r_imm_s8_patchable(r, imm) do { \
EMIT_REX_IF(0, 0, r); \
EMIT_OP(0xb8 + ((r)&7)); \
EMIT((s8)(imm), u32); \
} while (0)
#define emith_move_r_imm_s8_patch(ptr, imm) do { \
u8 *ptr_ = ptr; \
while ((*ptr_ & 0xf8) != 0xb8) ptr_++; \
EMIT_PTR(ptr_ + 1, (s8)(imm), u32); \
} while (0)
#define emith_arith_r_imm(op, r, imm) do { \
EMIT_REX_IF(0, 0, r); \
@ -851,7 +859,6 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
#define emith_jump_patchable(target) \
emith_jump(target)
#define emith_jump_patchable_size() 5 /* JMP rel32 */
#define emith_jump_cond(cond, ptr) do { \
u32 disp = (u8 *)(ptr) - ((u8 *)tcache_ptr + 6); \
@ -867,15 +874,17 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
u32 disp_ = (u8 *)(target) - ((u8 *)(ptr) + 4); \
u32 offs_ = (*(u8 *)(ptr) == 0x0f) ? 2 : 1; \
EMIT_PTR((u8 *)(ptr) + offs_, disp_ - offs_, u32); \
if ((void *)(pos) != NULL) *(u8 **)(pos) = (u8 *)ptr; \
if ((void *)(pos) != NULL) *(u8 **)(pos) = (u8 *)ptr + offs_; \
} while (0)
#define emith_jump_patch_size() 6
#define emith_jump_patch_size() 4
#define emith_jump_patch_inrange(ptr, target) !0
#define emith_jump_at(ptr, target) do { \
u32 disp_ = (u8 *)(target) - ((u8 *)(ptr) + 5); \
EMIT_PTR(ptr, 0xe9, u8); \
EMIT_PTR((u8 *)(ptr) + 1, disp_, u32); \
} while (0)
#define emith_jump_at_size() 5
#define emith_call(ptr) do { \
u32 disp = (u8 *)(ptr) - ((u8 *)tcache_ptr + 5); \
@ -900,9 +909,9 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
#define emith_ret() \
EMIT_OP(0xc3)
#define emith_add_r_ret_imm(r, imm) do { \
emith_read_r_r_offs_ptr(r, xSP, 0); \
emith_add_r_r_ptr_imm(r, r, imm); \
#define emith_add_r_ret(r) do { \
EMIT_REX_IF(1, r, xSP); \
emith_deref_modrm(0x03, 0, r, xSP); /* add r, [xsp] */ \
} while (0)
#define emith_jump_reg(r) \
@ -974,7 +983,7 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
emith_move_r_imm(rd, imm); \
} while (0)
#define host_instructions_updated(base, end)
#define host_instructions_updated(base, end) (void)(base),(void)(end)
#define emith_update_cache() /**/
#define emith_rw_offs_max() 0xffffffff