X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=deps%2Flightrec%2Fregcache.c;h=45d77c6ccd578cd87db3cc5f693666004f265934;hb=2e6c828e00165e0a11ee44a144c7ec8ac24a4b60;hp=1f11d8a27ae81496a982796f0033e12d5b6234f4;hpb=ba3814c189d3bd2332b66fb6c633a7d028e618fe;p=pcsx_rearmed.git diff --git a/deps/lightrec/regcache.c b/deps/lightrec/regcache.c index 1f11d8a2..45d77c6c 100644 --- a/deps/lightrec/regcache.c +++ b/deps/lightrec/regcache.c @@ -11,6 +11,8 @@ #include #include +#define REG_PC (offsetof(struct lightrec_state, curr_pc) / sizeof(u32)) + enum reg_priority { REG_IS_TEMP, REG_IS_TEMP_VALUE, @@ -24,7 +26,7 @@ enum reg_priority { struct native_register { bool used, output, extend, extended, zero_extend, zero_extended, locked; - s8 emulated_register; + s16 emulated_register; intptr_t value; enum reg_priority prio; }; @@ -47,6 +49,10 @@ static const char * mips_regs[] = { "lo", "hi", }; +/* Forward declaration(s) */ +static void clean_reg(jit_state_t *_jit, + struct native_register *nreg, u8 jit_reg, bool clean); + const char * lightrec_reg_name(u8 reg) { return mips_regs[reg]; @@ -61,7 +67,7 @@ static inline bool lightrec_reg_is_zero(u8 jit_reg) return false; } -static inline s8 lightrec_get_hardwired_reg(u8 reg) +static inline s8 lightrec_get_hardwired_reg(u16 reg) { #if defined(__mips__) || defined(__alpha__) || defined(__riscv) if (reg == 0) @@ -146,7 +152,7 @@ static struct native_register * alloc_temp(struct regcache *cache) for (i = ARRAY_SIZE(cache->lightrec_regs); i; i--) { elm = &cache->lightrec_regs[i - 1]; - if (!elm->used && elm->prio < best) { + if (!elm->used && !elm->locked && elm->prio < best) { nreg = elm; best = elm->prio; @@ -159,7 +165,7 @@ static struct native_register * alloc_temp(struct regcache *cache) } static struct native_register * find_mapped_reg(struct regcache *cache, - u8 reg, bool out) + u16 reg, bool out) { unsigned int i; @@ -175,7 +181,7 @@ static struct native_register * find_mapped_reg(struct regcache *cache, } static struct native_register * alloc_in_out(struct regcache *cache, - u8 reg, bool out) + u16 reg, bool out) { struct native_register *elm, *nreg = NULL; enum reg_priority best = REG_NB_PRIORITIES; @@ -191,7 +197,7 @@ static struct native_register * alloc_in_out(struct regcache *cache, for (i = 0; i < ARRAY_SIZE(cache->lightrec_regs); i++) { elm = &cache->lightrec_regs[i]; - if (!elm->used && elm->prio < best) { + if (!elm->used && !elm->locked && elm->prio < best) { nreg = elm; best = elm->prio; @@ -217,14 +223,7 @@ static void lightrec_discard_nreg(struct native_register *nreg) static void lightrec_unload_nreg(struct regcache *cache, jit_state_t *_jit, struct native_register *nreg, u8 jit_reg) { - /* If we get a dirty register, store back the old value */ - if (nreg->prio == REG_IS_DIRTY) { - s16 offset = offsetof(struct lightrec_state, regs.gpr) - + (nreg->emulated_register << 2); - - jit_stxi_i(offset, LIGHTREC_REG_STATE, jit_reg); - } - + clean_reg(_jit, nreg, jit_reg, false); lightrec_discard_nreg(nreg); } @@ -237,21 +236,6 @@ void lightrec_unload_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg) lightning_reg_to_lightrec(cache, jit_reg), jit_reg); } -/* lightrec_lock_reg: the register will be cleaned if dirty, then locked. - * A locked register cannot only be used as input, not output. */ -void lightrec_lock_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg) -{ - struct native_register *reg; - - if (lightrec_reg_is_zero(jit_reg)) - return; - - reg = lightning_reg_to_lightrec(cache, jit_reg); - lightrec_clean_reg(cache, _jit, jit_reg); - - reg->locked = true; -} - u8 lightrec_alloc_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg) { struct native_register *reg; @@ -312,8 +296,23 @@ void lightrec_temp_set_value(struct regcache *cache, u8 jit_reg, intptr_t value) nreg->value = value; } +u8 lightrec_alloc_reg_temp_with_value(struct regcache *cache, + jit_state_t *_jit, intptr_t value) +{ + s8 reg; + + reg = lightrec_get_reg_with_value(cache, value); + if (reg < 0) { + reg = lightrec_alloc_reg_temp(cache, _jit); + jit_movi((u8)reg, value); + lightrec_temp_set_value(cache, (u8)reg, value); + } + + return (u8)reg; +} + u8 lightrec_alloc_reg_out(struct regcache *cache, jit_state_t *_jit, - u8 reg, u8 flags) + u16 reg, u8 flags) { struct native_register *nreg; u8 jit_reg; @@ -347,7 +346,7 @@ u8 lightrec_alloc_reg_out(struct regcache *cache, jit_state_t *_jit, } u8 lightrec_alloc_reg_in(struct regcache *cache, jit_state_t *_jit, - u8 reg, u8 flags) + u16 reg, u8 flags) { struct native_register *nreg; u8 jit_reg; @@ -416,33 +415,132 @@ u8 lightrec_alloc_reg_in(struct regcache *cache, jit_state_t *_jit, return jit_reg; } -u8 lightrec_request_reg_in(struct regcache *cache, jit_state_t *_jit, - u8 reg, u8 jit_reg) +void lightrec_remap_reg(struct regcache *cache, jit_state_t *_jit, + u8 jit_reg, u16 reg_out, bool discard) { struct native_register *nreg; + + lightrec_discard_reg_if_loaded(cache, reg_out); + + nreg = lightning_reg_to_lightrec(cache, jit_reg); + clean_reg(_jit, nreg, jit_reg, !discard); + + nreg->output = true; + nreg->emulated_register = reg_out; + nreg->extend = nreg->extended; + nreg->zero_extend = nreg->zero_extended; +} + +static bool reg_pc_is_mapped(struct regcache *cache) +{ + struct native_register *nreg = lightning_reg_to_lightrec(cache, JIT_V0); + + return nreg->prio == REG_IS_LOADED && nreg->emulated_register == REG_PC; +} + +void lightrec_load_imm(struct regcache *cache, + jit_state_t *_jit, u8 jit_reg, u32 pc, u32 imm) +{ + s32 delta = imm - pc; + + if (!reg_pc_is_mapped(cache) || !can_sign_extend(delta, 16)) + jit_movi(jit_reg, imm); + else if (jit_reg != JIT_V0 || delta) + jit_addi(jit_reg, JIT_V0, delta); +} + +void lightrec_load_next_pc_imm(struct regcache *cache, + jit_state_t *_jit, u32 pc, u32 imm) +{ + struct native_register *nreg = lightning_reg_to_lightrec(cache, JIT_V0); + u8 reg = JIT_V0; + + if (lightrec_store_next_pc()) + reg = lightrec_alloc_reg_temp(cache, _jit); + + if (reg_pc_is_mapped(cache)) { + /* JIT_V0 contains next PC - so we can overwrite it */ + lightrec_load_imm(cache, _jit, reg, pc, imm); + } else { + /* JIT_V0 contains something else - invalidate it */ + if (reg == JIT_V0) + lightrec_unload_reg(cache, _jit, JIT_V0); + + jit_movi(reg, imm); + } + + if (lightrec_store_next_pc()) { + jit_stxi_i(offsetof(struct lightrec_state, next_pc), + LIGHTREC_REG_STATE, reg); + lightrec_free_reg(cache, reg); + } else { + nreg->prio = REG_IS_LOADED; + nreg->emulated_register = -1; + nreg->locked = true; + } +} + +void lightrec_load_next_pc(struct regcache *cache, jit_state_t *_jit, u8 reg) +{ + struct native_register *nreg_v0, *nreg; u16 offset; + u8 jit_reg; - nreg = find_mapped_reg(cache, reg, false); - if (nreg) { - jit_reg = lightrec_reg_to_lightning(cache, nreg); - nreg->used = true; - return jit_reg; + if (lightrec_store_next_pc()) { + jit_reg = lightrec_alloc_reg_in(cache, _jit, reg, 0); + offset = offsetof(struct lightrec_state, next_pc); + jit_stxi_i(offset, LIGHTREC_REG_STATE, jit_reg); + lightrec_free_reg(cache, jit_reg); + + return; } - nreg = lightning_reg_to_lightrec(cache, jit_reg); - lightrec_unload_nreg(cache, _jit, nreg, jit_reg); + /* Invalidate JIT_V0 if it is not mapped to 'reg' */ + nreg_v0 = lightning_reg_to_lightrec(cache, JIT_V0); + if (nreg_v0->prio >= REG_IS_LOADED && nreg_v0->emulated_register != reg) + lightrec_unload_nreg(cache, _jit, nreg_v0, JIT_V0); - /* Load previous value from register cache */ - offset = offsetof(struct lightrec_state, regs.gpr) + (reg << 2); - jit_ldxi_i(jit_reg, LIGHTREC_REG_STATE, offset); + nreg = find_mapped_reg(cache, reg, false); + if (!nreg) { + /* Not mapped - load the value from the register cache */ - nreg->extended = true; - nreg->zero_extended = false; - nreg->used = true; - nreg->emulated_register = reg; - nreg->prio = REG_IS_LOADED; + offset = offsetof(struct lightrec_state, regs.gpr) + (reg << 2); + jit_ldxi_ui(JIT_V0, LIGHTREC_REG_STATE, offset); - return jit_reg; + nreg_v0->prio = REG_IS_LOADED; + nreg_v0->emulated_register = reg; + + } else if (nreg == nreg_v0) { + /* The target register 'reg' is mapped to JIT_V0 */ + + if (!nreg->zero_extended) + jit_extr_ui(JIT_V0, JIT_V0); + + } else { + /* The target register 'reg' is mapped elsewhere. In that case, + * move the register's value to JIT_V0 and re-map it in the + * register cache. We can then safely discard the original + * mapped register (even if it was dirty). */ + + jit_reg = lightrec_reg_to_lightning(cache, nreg); + if (nreg->zero_extended) + jit_movr(JIT_V0, jit_reg); + else + jit_extr_ui(JIT_V0, jit_reg); + + *nreg_v0 = *nreg; + lightrec_discard_nreg(nreg); + } + + if (lightrec_store_next_pc()) { + jit_stxi_i(offsetof(struct lightrec_state, next_pc), + LIGHTREC_REG_STATE, JIT_V0); + } else { + lightrec_clean_reg(cache, _jit, JIT_V0); + + nreg_v0->zero_extended = true; + nreg_v0->locked = true; + } } static void free_reg(struct native_register *nreg) @@ -474,6 +572,7 @@ void lightrec_free_regs(struct regcache *cache) static void clean_reg(jit_state_t *_jit, struct native_register *nreg, u8 jit_reg, bool clean) { + /* If we get a dirty register, store back the old value */ if (nreg->prio == REG_IS_DIRTY) { s16 offset = offsetof(struct lightrec_state, regs.gpr) + (nreg->emulated_register << 2); @@ -534,8 +633,13 @@ void lightrec_clean_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg) } } +bool lightrec_reg_is_loaded(struct regcache *cache, u16 reg) +{ + return !!find_mapped_reg(cache, reg, false); +} + void lightrec_clean_reg_if_loaded(struct regcache *cache, jit_state_t *_jit, - u8 reg, bool unload) + u16 reg, bool unload) { struct native_register *nreg; u8 jit_reg; @@ -551,7 +655,7 @@ void lightrec_clean_reg_if_loaded(struct regcache *cache, jit_state_t *_jit, } } -void lightrec_discard_reg_if_loaded(struct regcache *cache, u8 reg) +void lightrec_discard_reg_if_loaded(struct regcache *cache, u16 reg) { struct native_register *nreg; @@ -584,6 +688,19 @@ void lightrec_regcache_reset(struct regcache *cache) memset(&cache->lightrec_regs, 0, sizeof(cache->lightrec_regs)); } +void lightrec_preload_pc(struct regcache *cache, jit_state_t *_jit) +{ + struct native_register *nreg; + + /* The block's PC is loaded in JIT_V0 at the start of the block */ + nreg = lightning_reg_to_lightrec(cache, JIT_V0); + nreg->emulated_register = REG_PC; + nreg->prio = REG_IS_LOADED; + nreg->zero_extended = true; + + jit_live(JIT_V0); +} + struct regcache * lightrec_regcache_init(struct lightrec_state *state) { struct regcache *cache;