From ed7c6238b7528f1d919798e452570108c186ec48 Mon Sep 17 00:00:00 2001 From: kub Date: Wed, 26 Jan 2022 19:46:51 +0000 Subject: [PATCH] sh2 drc, optimisation for mips,riscv --- cpu/drc/emit_mips.c | 107 ++++++++++++++++++++++++++++++++++++------- cpu/drc/emit_riscv.c | 9 +++- 2 files changed, 98 insertions(+), 18 deletions(-) diff --git a/cpu/drc/emit_mips.c b/cpu/drc/emit_mips.c index 35d928e3..a65f1204 100644 --- a/cpu/drc/emit_mips.c +++ b/cpu/drc/emit_mips.c @@ -235,8 +235,8 @@ enum { RB_SRL=0, RB_ROTR=1 }; #define MIPS_BGT (OP_BGTZ << 5) // rs > 0 #define MIPS_BLT ((OP__RT << 5)|RT_BLTZ) // rs < 0 #define MIPS_BGE ((OP__RT << 5)|RT_BGEZ) // rs >= 0 -#define MIPS_BGTL ((OP__RT << 5)|RT_BLTZAL) // rs > 0, link $ra if jumping -#define MIPS_BGEL ((OP__RT << 5)|RT_BGEZAL) // rs >= 0, link $ra if jumping +#define MIPS_BLTL ((OP__RT << 5)|RT_BLTZAL) // rs > 0, always link $ra +#define MIPS_BGEL ((OP__RT << 5)|RT_BGEZAL) // rs >= 0, always link $ra #define MIPS_BCOND(cond, rs, rt, offs16) \ MIPS_OP_IMM((cond >> 5), rt, rs, (offs16) >> 2) @@ -809,20 +809,71 @@ static void emith_set_compare_flags(int rs, int rt, s32 imm) // move immediate +#define MAX_HOST_LITERALS 32 // pool must be smaller than 32 KB +static uintptr_t literal_pool[MAX_HOST_LITERALS]; +static u32 *literal_insn[MAX_HOST_LITERALS]; +static int literal_pindex, literal_iindex; + +static inline int emith_pool_literal(uintptr_t imm) +{ + int idx = literal_pindex - 8; // max look behind in pool + // see if one of the last literals was the same + for (idx = (idx < 0 ? 0 : idx); idx < literal_pindex; idx++) + if (imm == literal_pool[idx]) + break; + if (idx == literal_pindex) // store new literal + literal_pool[literal_pindex++] = imm; + return idx; +} + +static void emith_pool_commit(int jumpover) +{ + int i, sz = literal_pindex * sizeof(uintptr_t); + u8 *pool = (u8 *)tcache_ptr; + + // nothing to commit if pool is empty + if (sz == 0) + return; + // align pool to pointer size + if (jumpover) + pool += sizeof(u32); + i = (uintptr_t)pool & (sizeof(void *)-1); + pool += (i ? sizeof(void *)-i : 0); + // need branch over pool if not at block end + if (jumpover) + emith_branch(MIPS_B(sz + (pool-(u8 *)tcache_ptr))); + emith_flush(); + // safety check - pool must be after insns and reachable + if ((u32)(pool - (u8 *)literal_insn[0] + 8) > 0x7fff) { + elprintf(EL_STATUS|EL_SVP|EL_ANOMALY, + "pool offset out of range"); + exit(1); + } + // copy pool and adjust addresses in insns accessing the pool + memcpy(pool, literal_pool, sz); + for (i = 0; i < literal_iindex; i++) { + u32 *pi = literal_insn[i]; + *pi = (*pi & 0xffff0000) | (u16)(*pi + ((u8 *)pool - (u8 *)pi)); + } + // count pool constants as insns for statistics + for (i = 0; i < literal_pindex * sizeof(uintptr_t)/sizeof(u32); i++) + COUNT_OP; + + tcache_ptr = (void *)((u8 *)pool + sz); + literal_pindex = literal_iindex = 0; +} + +static void emith_pool_check(void) +{ + // check if pool must be committed + if (literal_iindex > MAX_HOST_LITERALS-4 || (literal_pindex && + (u8 *)tcache_ptr - (u8 *)literal_insn[0] > 0x7000)) + // pool full, or displacement is approaching the limit + emith_pool_commit(1); +} + static void emith_move_imm(int r, uintptr_t imm) { -#if _MIPS_SZPTR == 64 - if ((s32)imm != imm) { - emith_move_imm(r, imm >> 32); - if (imm & 0xffff0000) { - EMIT(MIPS_DLSL_IMM(r, r, 16)); - EMIT(MIPS_OR_IMM(r, r, (imm >> 16) & 0xffff)); - EMIT(MIPS_DLSL_IMM(r, r, 16)); - } else EMIT(MIPS_DLSL32_IMM(r, r, 0)); - if (imm & 0x0000ffff) - EMIT(MIPS_OR_IMM(r, r, imm & 0xffff)); - } else -#endif if ((s16)imm == imm) { EMIT(MIPS_ADD_IMM(r, Z0, imm)); } else if (!((u32)imm >> 16)) { @@ -837,9 +888,33 @@ static void emith_move_imm(int r, uintptr_t imm) EMIT(MIPS_OR_IMM(r, s, (u16)imm)); } } +static void emith_move_ptr_imm(int r, uintptr_t imm) +{ +#if _MIPS_SZPTR == 64 + uintptr_t offs = (u8 *)imm - (u8 *)tcache_ptr - 8; + if ((s32)imm != imm && (s32)offs == offs) { + // PC relative + emith_flush(); // next insn must not change its position at all + EMIT_PTR(tcache_ptr, MIPS_BCONDZ(MIPS_BLTL, Z0, 0)); // loads PC+8 into LR + emith_move_imm(r, offs); + emith_add_r_r_r_ptr(r, LR, r); + } else if ((s32)imm != imm) { + // via literal pool + int idx; + if (literal_iindex >= MAX_HOST_LITERALS) + emith_pool_commit(1); + idx = emith_pool_literal(imm); + emith_flush(); // next 2 must not change their position at all + EMIT_PTR(tcache_ptr, MIPS_BCONDZ(MIPS_BLTL, Z0, 0)); // loads PC+8 into LR + literal_insn[literal_iindex++] = (u32 *)tcache_ptr; + EMIT_PTR(tcache_ptr, MIPS_OP_IMM(OP_LP, r, LR, idx*sizeof(uintptr_t) - 4)); + } else +#endif + emith_move_imm(r, imm); +} #define emith_move_r_ptr_imm(r, imm) \ - emith_move_imm(r, (uintptr_t)(imm)) + emith_move_ptr_imm(r, (uintptr_t)(imm)) #define emith_move_r_imm(r, imm) \ emith_move_imm(r, (s32)(imm)) @@ -1580,8 +1655,6 @@ static int emith_cond_check(int cond, int *r) // emitter ABI stuff -#define emith_pool_check() /**/ -#define emith_pool_commit(j) /**/ #define emith_update_cache() /**/ #define emith_rw_offs_max() 0x7fff #define emith_uext_ptr(r) /**/ diff --git a/cpu/drc/emit_riscv.c b/cpu/drc/emit_riscv.c index 04121772..35ee0168 100644 --- a/cpu/drc/emit_riscv.c +++ b/cpu/drc/emit_riscv.c @@ -713,7 +713,14 @@ static void emith_move_imm(int r, uintptr_t imm) static void emith_move_ptr_imm(int r, uintptr_t imm) { #if __riscv_xlen == 64 - if ((s32)imm != imm) { + uintptr_t offs = (u8 *)imm - (u8 *)tcache_ptr; + if ((s32)imm != imm && (s32)offs == offs) { + // PC relative + EMIT(R5_MOVA_IMM(r, offs + _CB(offs,1,11,12))); + if (offs & 0xfff) + EMIT(R5_ADD_IMM(r, r, offs)); + } else if ((s32)imm != imm) { + // via literal pool int idx; if (literal_iindex >= MAX_HOST_LITERALS) emith_pool_commit(1); -- 2.39.5