X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=deps%2Flightrec%2Flightrec.c;h=ffa40f0938af4634c1607ad014cac6e269ceaa3f;hb=07d178b5ed0a9861bd8936aeeb71a6cd2f713eb4;hp=d172a30adb26ba5f08357e3a03fb920bea755578;hpb=02487de7ff9fcbb6d7d692a6b3ae6e6539708abc;p=pcsx_rearmed.git diff --git a/deps/lightrec/lightrec.c b/deps/lightrec/lightrec.c index d172a30a..ffa40f09 100644 --- a/deps/lightrec/lightrec.c +++ b/deps/lightrec/lightrec.c @@ -27,9 +27,6 @@ #include #include #include -#if ENABLE_TINYMM -#include -#endif #define GENMASK(h, l) \ (((uintptr_t)-1 << (l)) & ((uintptr_t)-1 >> (__WORDSIZE - 1 - (h)))) @@ -244,7 +241,7 @@ lightrec_get_map(struct lightrec_state *state, void **host, u32 kaddr) } u32 lightrec_rw(struct lightrec_state *state, union code op, - u32 addr, u32 data, u16 *flags, struct block *block) + u32 addr, u32 data, u32 *flags, struct block *block) { const struct lightrec_mem_map *map; const struct lightrec_mem_map_ops *ops; @@ -312,7 +309,7 @@ u32 lightrec_rw(struct lightrec_state *state, union code op, } static void lightrec_rw_helper(struct lightrec_state *state, - union code op, u16 *flags, + union code op, u32 *flags, struct block *block) { u32 ret = lightrec_rw(state, op, state->regs.gpr[op.i.rs], @@ -328,22 +325,22 @@ static void lightrec_rw_helper(struct lightrec_state *state, case OP_LW: if (op.i.rt) state->regs.gpr[op.i.rt] = ret; - default: /* fall-through */ + fallthrough; + default: break; } } -static void lightrec_rw_cb(struct lightrec_state *state) +static void lightrec_rw_cb(struct lightrec_state *state, u32 arg) { - lightrec_rw_helper(state, (union code)state->c_wrapper_arg, NULL, NULL); + lightrec_rw_helper(state, (union code) arg, NULL, NULL); } -static void lightrec_rw_generic_cb(struct lightrec_state *state) +static void lightrec_rw_generic_cb(struct lightrec_state *state, u32 arg) { struct block *block; struct opcode *op; bool was_tagged; - u32 arg = state->c_wrapper_arg; u16 offset = (u16)arg; block = lightrec_find_block_from_lut(state->block_cache, @@ -364,6 +361,7 @@ static void lightrec_rw_generic_cb(struct lightrec_state *state) "for recompilation\n", block->pc); block->flags |= BLOCK_SHOULD_RECOMPILE; + lut_write(state, lut_offset(block->pc), NULL); } } @@ -372,6 +370,16 @@ static u32 clamp_s32(s32 val, s32 min, s32 max) return val < min ? min : val > max ? max : val; } +static u16 load_u16(u32 *ptr) +{ + return ((struct u16x2 *) ptr)->l; +} + +static void store_u16(u32 *ptr, u16 value) +{ + ((struct u16x2 *) ptr)->l = value; +} + static u32 lightrec_mfc2(struct lightrec_state *state, u8 reg) { s16 gteir1, gteir2, gteir3; @@ -384,25 +392,26 @@ static u32 lightrec_mfc2(struct lightrec_state *state, u8 reg) case 9: case 10: case 11: - return (s32)(s16) state->regs.cp2d[reg]; + return (s32)(s16) load_u16(&state->regs.cp2d[reg]); case 7: case 16: case 17: case 18: case 19: - return (u16) state->regs.cp2d[reg]; + return load_u16(&state->regs.cp2d[reg]); case 28: case 29: - gteir1 = (s16) state->regs.cp2d[9]; - gteir2 = (s16) state->regs.cp2d[10]; - gteir3 = (s16) state->regs.cp2d[11]; + gteir1 = (s16) load_u16(&state->regs.cp2d[9]); + gteir2 = (s16) load_u16(&state->regs.cp2d[10]); + gteir3 = (s16) load_u16(&state->regs.cp2d[11]); return clamp_s32(gteir1 >> 7, 0, 0x1f) << 0 | clamp_s32(gteir2 >> 7, 0, 0x1f) << 5 | clamp_s32(gteir3 >> 7, 0, 0x1f) << 10; case 15: reg = 14; - default: /* fall-through */ + fallthrough; + default: return state->regs.cp2d[reg]; } } @@ -503,7 +512,8 @@ static void lightrec_mtc2(struct lightrec_state *state, u8 reg, u32 data) return; case 30: state->regs.cp2d[31] = count_leading_bits((s32) data); - default: /* fall-through */ + fallthrough; + default: state->regs.cp2d[reg] = data; break; } @@ -519,15 +529,15 @@ static void lightrec_ctc2(struct lightrec_state *state, u8 reg, u32 data) case 27: case 29: case 30: - data = (s32)(s16) data; + store_u16(&state->regs.cp2c[reg], data); break; case 31: data = (data & 0x7ffff000) | !!(data & 0x7f87e000) << 31; - default: /* fall-through */ + fallthrough; + default: + state->regs.cp2c[reg] = data; break; } - - state->regs.cp2c[reg] = data; } void lightrec_mtc(struct lightrec_state *state, union code op, u32 data) @@ -540,9 +550,9 @@ void lightrec_mtc(struct lightrec_state *state, union code op, u32 data) lightrec_mtc2(state, op.r.rd, data); } -static void lightrec_mtc_cb(struct lightrec_state *state) +static void lightrec_mtc_cb(struct lightrec_state *state, u32 arg) { - union code op = (union code) state->c_wrapper_arg; + union code op = (union code) arg; lightrec_mtc(state, op, state->regs.gpr[op.r.rt]); } @@ -571,9 +581,9 @@ void lightrec_cp(struct lightrec_state *state, union code op) (*state->ops.cop2_op)(state, op.opcode); } -static void lightrec_cp_cb(struct lightrec_state *state) +static void lightrec_cp_cb(struct lightrec_state *state, u32 arg) { - lightrec_cp(state, (union code) state->c_wrapper_arg); + lightrec_cp(state, (union code) arg); } static void lightrec_syscall_cb(struct lightrec_state *state) @@ -586,7 +596,7 @@ static void lightrec_break_cb(struct lightrec_state *state) lightrec_set_exit_flags(state, LIGHTREC_EXIT_BREAK); } -struct block * lightrec_get_block(struct lightrec_state *state, u32 pc) +static struct block * lightrec_get_block(struct lightrec_state *state, u32 pc) { struct block *block = lightrec_find_block(state->block_cache, pc); @@ -623,9 +633,10 @@ static void * get_next_block_func(struct lightrec_state *state, u32 pc) struct block *block; bool should_recompile; void *func; + int err; for (;;) { - func = lut_read(state, pc); + func = lut_read(state, lut_offset(pc)); if (func && func != state->get_next_block) break; @@ -647,10 +658,15 @@ static void * get_next_block_func(struct lightrec_state *state, u32 pc) lightrec_unregister(MEM_FOR_CODE, block->code_size); - if (ENABLE_THREADED_COMPILER) + if (ENABLE_THREADED_COMPILER) { lightrec_recompiler_add(state->rec, block); - else - lightrec_compile_block(state->cstate, block); + } else { + err = lightrec_compile_block(state->cstate, block); + if (err) { + state->exit_flags = LIGHTREC_EXIT_NOMEM; + return NULL; + } + } } if (ENABLE_THREADED_COMPILER && likely(!should_recompile)) @@ -672,7 +688,11 @@ static void * get_next_block_func(struct lightrec_state *state, u32 pc) pc = lightrec_emulate_block(state, block, pc); /* Then compile it using the profiled data */ - lightrec_compile_block(state->cstate, block); + err = lightrec_compile_block(state->cstate, block); + if (err) { + state->exit_flags = LIGHTREC_EXIT_NOMEM; + return NULL; + } } else { lightrec_recompiler_add(state->rec, block); } @@ -687,16 +707,58 @@ static void * get_next_block_func(struct lightrec_state *state, u32 pc) } static s32 c_function_wrapper(struct lightrec_state *state, s32 cycles_delta, - void (*f)(struct lightrec_state *)) + void (*f)(struct lightrec_state *, u32), u32 arg) { state->current_cycle = state->target_cycle - cycles_delta; - (*f)(state); + (*f)(state, arg); return state->target_cycle - state->current_cycle; } +static void * lightrec_alloc_code(struct lightrec_state *state, size_t size) +{ + void *code; + + if (ENABLE_THREADED_COMPILER) + lightrec_code_alloc_lock(state); + + code = tlsf_malloc(state->tlsf, size); + + if (ENABLE_THREADED_COMPILER) + lightrec_code_alloc_unlock(state); + + return code; +} + +static void lightrec_realloc_code(struct lightrec_state *state, + void *ptr, size_t size) +{ + /* NOTE: 'size' MUST be smaller than the size specified during + * the allocation. */ + + if (ENABLE_THREADED_COMPILER) + lightrec_code_alloc_lock(state); + + tlsf_realloc(state->tlsf, ptr, size); + + if (ENABLE_THREADED_COMPILER) + lightrec_code_alloc_unlock(state); +} + +static void lightrec_free_code(struct lightrec_state *state, void *ptr) +{ + if (ENABLE_THREADED_COMPILER) + lightrec_code_alloc_lock(state); + + tlsf_free(state->tlsf, ptr); + + if (ENABLE_THREADED_COMPILER) + lightrec_code_alloc_unlock(state); +} + static void * lightrec_emit_code(struct lightrec_state *state, + const struct block *block, jit_state_t *_jit, unsigned int *size) { bool has_code_buffer = ENABLE_CODE_BUFFER && state->tlsf; @@ -710,9 +772,28 @@ static void * lightrec_emit_code(struct lightrec_state *state, if (has_code_buffer) { jit_get_code(&code_size); - code = tlsf_malloc(state->tlsf, (size_t) code_size); - if (!code) - return NULL; + code = lightrec_alloc_code(state, (size_t) code_size); + + if (!code) { + if (ENABLE_THREADED_COMPILER) { + /* If we're using the threaded compiler, return + * an allocation error here. The threaded + * compiler will then empty its job queue and + * request a code flush using the reaper. */ + return NULL; + } + + /* Remove outdated blocks, and try again */ + lightrec_remove_outdated_blocks(state->block_cache, block); + + pr_debug("Re-try to alloc %zu bytes...\n", code_size); + + code = lightrec_alloc_code(state, code_size); + if (!code) { + pr_err("Could not alloc even after removing old blocks!\n"); + return NULL; + } + } jit_set_code(code, code_size); } @@ -723,7 +804,7 @@ static void * lightrec_emit_code(struct lightrec_state *state, lightrec_register(MEM_FOR_CODE, new_code_size); if (has_code_buffer) { - tlsf_realloc(state->tlsf, code, new_code_size); + lightrec_realloc_code(state, code, (size_t) new_code_size); pr_debug("Creating code block at address 0x%" PRIxPTR ", " "code size: %" PRIuPTR " new: %" PRIuPTR "\n", @@ -776,6 +857,8 @@ static struct block * generate_wrapper(struct lightrec_state *state) for (i = 0; i < NUM_TEMPS; i++) jit_stxi(stack_ptr + i * sizeof(uintptr_t), JIT_FP, JIT_R(i)); + jit_getarg(JIT_R1, jit_arg()); + /* Jump to the trampoline */ to_tramp = jit_jmpi(); @@ -808,6 +891,7 @@ static struct block * generate_wrapper(struct lightrec_state *state) jit_pushargr(LIGHTREC_REG_STATE); jit_pushargr(LIGHTREC_REG_CYCLE); jit_pushargr(JIT_R0); + jit_pushargr(JIT_R1); jit_finishi(c_function_wrapper); jit_retval_i(LIGHTREC_REG_CYCLE); @@ -819,7 +903,7 @@ static struct block * generate_wrapper(struct lightrec_state *state) block->flags = 0; block->nb_ops = 0; - block->function = lightrec_emit_code(state, _jit, + block->function = lightrec_emit_code(state, block, _jit, &block->code_size); if (!block->function) goto err_free_block; @@ -1002,7 +1086,7 @@ static struct block * generate_dispatcher(struct lightrec_state *state) block->flags = 0; block->nb_ops = 0; - block->function = lightrec_emit_code(state, _jit, + block->function = lightrec_emit_code(state, block, _jit, &block->code_size); if (!block->function) goto err_free_block; @@ -1124,6 +1208,7 @@ static struct block * lightrec_precompile_block(struct lightrec_state *state, block->next = NULL; block->flags = 0; block->code_size = 0; + block->precompile_date = state->current_cycle; #if ENABLE_THREADED_COMPILER block->op_list_freed = (atomic_flag)ATOMIC_FLAG_INIT; #endif @@ -1189,7 +1274,8 @@ static bool lightrec_block_is_fully_tagged(const struct block *block) case OP_SWC2: if (!LIGHTREC_FLAGS_GET_IO_MODE(op->flags)) return false; - default: /* fall-through */ + fallthrough; + default: continue; } } @@ -1215,7 +1301,7 @@ static void lightrec_free_function(struct lightrec_state *state, void *fn) { if (ENABLE_CODE_BUFFER && state->tlsf) { pr_debug("Freeing code block at 0x%" PRIxPTR "\n", (uintptr_t) fn); - tlsf_free(state->tlsf, fn); + lightrec_free_code(state, fn); } } @@ -1235,7 +1321,7 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, jit_state_t *_jit, *oldjit; jit_node_t *start_of_block; bool skip_next = false; - void *old_fn; + void *old_fn, *new_fn; unsigned int i, j; u32 offset; @@ -1270,18 +1356,15 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, continue; } - cstate->cycles += lightrec_cycles_of_opcode(elm->c); - if (should_emulate(elm)) { pr_debug("Branch at offset 0x%x will be emulated\n", i << 2); lightrec_emit_eob(cstate, block, i, false); - skip_next = !(elm->flags & LIGHTREC_NO_DS); + skip_next = !op_flag_no_ds(elm->flags); } else { lightrec_rec_opcode(cstate, block, i); - skip_next = has_delay_slot(elm->c) && - !(elm->flags & LIGHTREC_NO_DS); + skip_next = !op_flag_no_ds(elm->flags) && has_delay_slot(elm->c); #if _WIN32 /* FIXME: GNU Lightning on Windows seems to use our * mapped registers as temporaries. Until the actual bug @@ -1290,6 +1373,8 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, lightrec_regcache_mark_live(cstate->reg_cache, _jit); #endif } + + cstate->cycles += lightrec_cycles_of_opcode(elm->c); } for (i = 0; i < cstate->nb_branches; i++) @@ -1318,20 +1403,20 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, pr_err("Unable to find branch target\n"); } - jit_ldxi(JIT_R0, LIGHTREC_REG_STATE, - offsetof(struct lightrec_state, eob_wrapper_func)); - - jit_jmpr(JIT_R0); - + jit_patch_abs(jit_jmpi(), state->eob_wrapper_func); jit_ret(); jit_epilog(); - block->function = lightrec_emit_code(state, _jit, - &block->code_size); - if (!block->function) { - pr_err("Unable to compile block!\n"); + new_fn = lightrec_emit_code(state, block, _jit, &block->code_size); + if (!new_fn) { + if (!ENABLE_THREADED_COMPILER) + pr_err("Unable to compile block!\n"); + block->_jit = oldjit; + _jit_destroy_state(_jit); + return -ENOMEM; } + block->function = new_fn; block->flags &= ~BLOCK_SHOULD_RECOMPILE; /* Add compiled function to the LUT */ @@ -1504,8 +1589,10 @@ void lightrec_free_block(struct lightrec_state *state, struct block *block) lightrec_free_opcode_list(state, block); if (block->_jit) _jit_destroy_state(block->_jit); - lightrec_free_function(state, block->function); - lightrec_unregister(MEM_FOR_CODE, block->code_size); + if (block->function) { + lightrec_free_function(state, block->function); + lightrec_unregister(MEM_FOR_CODE, block->code_size); + } lightrec_free(state, MEM_FOR_IR, sizeof(*block), block); } @@ -1539,7 +1626,7 @@ struct lightrec_state * lightrec_init(char *argv0, size_t nb, const struct lightrec_ops *ops) { - const struct lightrec_mem_map *codebuf_map; + const struct lightrec_mem_map *codebuf_map = &map[PSX_MAP_CODE_BUFFER]; struct lightrec_state *state; uintptr_t addr; void *tlsf = NULL; @@ -1552,9 +1639,8 @@ struct lightrec_state * lightrec_init(char *argv0, return NULL; } - if (ENABLE_CODE_BUFFER && nb > PSX_MAP_CODE_BUFFER) { - codebuf_map = &map[PSX_MAP_CODE_BUFFER]; - + if (ENABLE_CODE_BUFFER && nb > PSX_MAP_CODE_BUFFER + && codebuf_map->address) { tlsf = tlsf_create_with_pool(codebuf_map->address, codebuf_map->length); if (!tlsf) { @@ -1584,15 +1670,9 @@ struct lightrec_state * lightrec_init(char *argv0, state->tlsf = tlsf; state->with_32bit_lut = with_32bit_lut; -#if ENABLE_TINYMM - state->tinymm = tinymm_init(malloc, free, 4096); - if (!state->tinymm) - goto err_free_state; -#endif - state->block_cache = lightrec_blockcache_init(state); if (!state->block_cache) - goto err_free_tinymm; + goto err_free_state; if (ENABLE_THREADED_COMPILER) { state->rec = lightrec_recompiler_init(state); @@ -1668,11 +1748,7 @@ err_free_recompiler: lightrec_free_cstate(state->cstate); err_free_block_cache: lightrec_free_block_cache(state->block_cache); -err_free_tinymm: -#if ENABLE_TINYMM - tinymm_shutdown(state->tinymm); err_free_state: -#endif lightrec_unregister(MEM_FOR_LIGHTREC, sizeof(*state) + lut_elm_size(state) * CODE_LUT_SIZE); free(state); @@ -1689,6 +1765,10 @@ void lightrec_destroy(struct lightrec_state *state) state->current_cycle = ~state->current_cycle; lightrec_print_info(state); + lightrec_free_block_cache(state->block_cache); + lightrec_free_block(state, state->dispatcher); + lightrec_free_block(state, state->c_wrapper_block); + if (ENABLE_THREADED_COMPILER) { lightrec_free_recompiler(state->rec); lightrec_reaper_destroy(state->reaper); @@ -1696,16 +1776,10 @@ void lightrec_destroy(struct lightrec_state *state) lightrec_free_cstate(state->cstate); } - lightrec_free_block_cache(state->block_cache); - lightrec_free_block(state, state->dispatcher); - lightrec_free_block(state, state->c_wrapper_block); finish_jit(); if (ENABLE_CODE_BUFFER && state->tlsf) tlsf_destroy(state->tlsf); -#if ENABLE_TINYMM - tinymm_shutdown(state->tinymm); -#endif lightrec_unregister(MEM_FOR_LIGHTREC, sizeof(*state) + lut_elm_size(state) * CODE_LUT_SIZE); free(state); @@ -1714,17 +1788,23 @@ void lightrec_destroy(struct lightrec_state *state) void lightrec_invalidate(struct lightrec_state *state, u32 addr, u32 len) { u32 kaddr = kunseg(addr & ~0x3); - const struct lightrec_mem_map *map = lightrec_get_map(state, NULL, kaddr); - - if (map) { - if (map != &state->maps[PSX_MAP_KERNEL_USER_RAM]) - return; + enum psx_map idx = lightrec_get_map_idx(state, kaddr); + switch (idx) { + case PSX_MAP_MIRROR1: + case PSX_MAP_MIRROR2: + case PSX_MAP_MIRROR3: /* Handle mirrors */ - kaddr &= (state->maps[PSX_MAP_KERNEL_USER_RAM].length - 1); - - lightrec_invalidate_map(state, map, kaddr, len); + kaddr &= RAM_SIZE - 1; + fallthrough; + case PSX_MAP_KERNEL_USER_RAM: + break; + default: + return; } + + memset(lut_address(state, lut_offset(kaddr)), 0, + ((len + 3) / 4) * lut_elm_size(state)); } void lightrec_invalidate_all(struct lightrec_state *state)