Merge pull request #668 from pcercuei/update-lightrec-20220607
[pcsx_rearmed.git] / deps / lightrec / blockcache.c
index 4512392..70c5aeb 100644 (file)
@@ -63,8 +63,8 @@ void remove_from_code_lut(struct blockcache *cache, struct block *block)
        u32 offset = lut_offset(block->pc);
 
        if (block->function) {
-               memset(&state->code_lut[offset], 0,
-                      block->nb_ops * sizeof(*state->code_lut));
+               memset(lut_address(state, offset), 0,
+                      block->nb_ops * lut_elm_size(state));
        }
 }
 
@@ -102,18 +102,55 @@ void lightrec_unregister_block(struct blockcache *cache, struct block *block)
        pr_err("Block at PC 0x%x is not in cache\n", block->pc);
 }
 
-void lightrec_free_block_cache(struct blockcache *cache)
+static bool lightrec_block_is_old(const struct lightrec_state *state,
+                                 const struct block *block)
+{
+       u32 diff = state->current_cycle - block->precompile_date;
+
+       return diff > (1 << 27); /* About 4 seconds */
+}
+
+static void lightrec_free_blocks(struct blockcache *cache,
+                                const struct block *except, bool all)
 {
+       struct lightrec_state *state = cache->state;
        struct block *block, *next;
+       bool outdated = all;
        unsigned int i;
 
        for (i = 0; i < LUT_SIZE; i++) {
                for (block = cache->lut[i]; block; block = next) {
                        next = block->next;
-                       lightrec_free_block(cache->state, block);
+
+                       if (except && block == except)
+                               continue;
+
+                       if (!all) {
+                               outdated = lightrec_block_is_old(state, block) ||
+                                       lightrec_block_is_outdated(state, block);
+                       }
+
+                       if (outdated) {
+                               pr_debug("Freeing outdated block at PC 0x%08x\n", block->pc);
+                               remove_from_code_lut(cache, block);
+                               lightrec_unregister_block(cache, block);
+                               lightrec_free_block(state, block);
+                       }
                }
        }
+}
+
+void lightrec_remove_outdated_blocks(struct blockcache *cache,
+                                    const struct block *except)
+{
+       pr_info("Running out of code space. Cleaning block cache...\n");
+
+       lightrec_free_blocks(cache, except, false);
+}
 
+void lightrec_free_block_cache(struct blockcache *cache)
+{
+       lightrec_free_blocks(cache, NULL, true);
        lightrec_free(cache->state, MEM_FOR_LIGHTREC, sizeof(*cache), cache);
 }
 
@@ -152,10 +189,11 @@ u32 lightrec_calculate_block_hash(const struct block *block)
 
 bool lightrec_block_is_outdated(struct lightrec_state *state, struct block *block)
 {
-       void **lut_entry = &state->code_lut[lut_offset(block->pc)];
+       u32 offset = lut_offset(block->pc);
        bool outdated;
+       void *addr;
 
-       if (*lut_entry)
+       if (lut_read(state, offset))
                return false;
 
        outdated = block->hash != lightrec_calculate_block_hash(block);
@@ -163,9 +201,11 @@ bool lightrec_block_is_outdated(struct lightrec_state *state, struct block *bloc
                /* The block was marked as outdated, but the content is still
                 * the same */
                if (block->function)
-                       *lut_entry = block->function;
+                       addr = block->function;
                else
-                       *lut_entry = state->get_next_block;
+                       addr = state->get_next_block;
+
+               lut_write(state, offset, addr);
        }
 
        return outdated;