If recompiler block hash table points to wrong block, then walk tree to find correct block instead of recompiling. Speedups of 10-20% on games that were seeing hash aliasing, eg Quake III, System Shock 2, UltraHLE etc
This commit is contained in:
parent
c9111b22a2
commit
36bb949126
4 changed files with 169 additions and 2 deletions
|
|
@ -1292,7 +1292,7 @@ void exec386_dynarec(int cycs)
|
|||
int valid_block = 0;
|
||||
trap = 0;
|
||||
|
||||
if (block)
|
||||
if (block && !abrt)
|
||||
{
|
||||
page_t *page = &pages[phys_addr >> 12];
|
||||
|
||||
|
|
@ -1301,7 +1301,23 @@ void exec386_dynarec(int cycs)
|
|||
also catch any page faults at this stage*/
|
||||
valid_block = (block->pc == cs + pc) && (block->_cs == cs) &&
|
||||
(block->use32 == use32) && (block->phys == phys_addr) && (block->stack32 == stack32);
|
||||
|
||||
if (!valid_block)
|
||||
{
|
||||
uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
|
||||
|
||||
if (page->code_present_mask & mask)
|
||||
{
|
||||
/*Walk page tree to see if we find the correct block*/
|
||||
codeblock_t *new_block = codeblock_tree_find(phys_addr);
|
||||
if (new_block)
|
||||
{
|
||||
valid_block = (new_block->pc == cs + pc) && (new_block->_cs == cs) &&
|
||||
(new_block->use32 == use32) && (new_block->phys == phys_addr) && (new_block->stack32 == stack32);
|
||||
if (valid_block)
|
||||
block = new_block;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (valid_block && (block->page_mask & page->dirty_mask))
|
||||
{
|
||||
codegen_check_flush(page, page->dirty_mask, phys_addr);
|
||||
|
|
@ -1337,6 +1353,7 @@ void exec386_dynarec(int cycs)
|
|||
{
|
||||
void (*code)() = (void *)&block->data[BLOCK_START];
|
||||
|
||||
codeblock_hash[hash] = block;
|
||||
// if (output) pclog("Run block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%08x %04x %08x %08x %016llx %08x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, get_phys(cs+pc), block->phys, block->page_mask, block->endpc);
|
||||
|
||||
inrecomp=1;
|
||||
|
|
|
|||
138
src/codegen.h
138
src/codegen.h
|
|
@ -1,3 +1,5 @@
|
|||
#include "mem.h"
|
||||
|
||||
#ifdef __amd64__
|
||||
#include "codegen_x86-64.h"
|
||||
#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32
|
||||
|
|
@ -39,6 +41,10 @@ typedef struct codeblock_t
|
|||
struct codeblock_t *prev, *next;
|
||||
struct codeblock_t *prev_2, *next_2;
|
||||
|
||||
/*Pointers for codeblock tree, used to search for blocks when hash lookup
|
||||
fails.*/
|
||||
struct codeblock_t *parent, *left, *right;
|
||||
|
||||
uint32_t pc;
|
||||
uint32_t _cs;
|
||||
uint32_t endpc;
|
||||
|
|
@ -52,6 +58,138 @@ typedef struct codeblock_t
|
|||
uint8_t data[2048];
|
||||
} codeblock_t;
|
||||
|
||||
static inline codeblock_t *codeblock_tree_find(uint32_t phys)
|
||||
{
|
||||
codeblock_t *block = pages[phys >> 12].head;
|
||||
|
||||
while (block)
|
||||
{
|
||||
if (phys == block->phys)
|
||||
return block;
|
||||
else if (phys < block->phys)
|
||||
block = block->left;
|
||||
else
|
||||
block = block->right;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void codeblock_tree_add(codeblock_t *new_block)
|
||||
{
|
||||
codeblock_t *block = pages[new_block->phys >> 12].head;
|
||||
|
||||
if (!block)
|
||||
{
|
||||
pages[new_block->phys >> 12].head = new_block;
|
||||
new_block->parent = new_block->left = new_block->right = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
codeblock_t *old_block = NULL;
|
||||
while (block)
|
||||
{
|
||||
old_block = block;
|
||||
|
||||
if (new_block->phys < old_block->phys)
|
||||
block = block->left;
|
||||
else
|
||||
block = block->right;
|
||||
}
|
||||
|
||||
if (new_block->phys < old_block->phys)
|
||||
old_block->left = new_block;
|
||||
else
|
||||
old_block->right = new_block;
|
||||
|
||||
new_block->parent = old_block;
|
||||
new_block->left = new_block->right = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void codeblock_tree_delete(codeblock_t *block)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
codeblock_t *parent = block->parent;
|
||||
|
||||
if (!block->left && !block->right)
|
||||
{
|
||||
/*Easy case - remove from parent*/
|
||||
if (parent)
|
||||
{
|
||||
if (parent->left == block)
|
||||
parent->left = NULL;
|
||||
if (parent->right == block)
|
||||
parent->right = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (!block->left)
|
||||
{
|
||||
/*Only left node*/
|
||||
if (!parent)
|
||||
pages[block->phys >> 12].head = block->left;
|
||||
else
|
||||
{
|
||||
if (parent->left == block)
|
||||
parent->left = block->left;
|
||||
if (parent->right == block)
|
||||
parent->right = block->left;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (!block->right)
|
||||
{
|
||||
/*Only right node*/
|
||||
if (!parent)
|
||||
pages[block->phys >> 12].head = block->right;
|
||||
else
|
||||
{
|
||||
if (parent->left == block)
|
||||
parent->left = block->right;
|
||||
if (parent->right == block)
|
||||
parent->right = block->right;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*Difficult case - node has two children. Walk right child to find lowest node*/
|
||||
codeblock_t *lowest = block->right;
|
||||
codeblock_t *old_parent;
|
||||
|
||||
while (lowest->left)
|
||||
lowest = lowest->left;
|
||||
old_parent = lowest->parent;
|
||||
|
||||
/*Replace deleted node with lowest node*/
|
||||
if (!parent)
|
||||
pages[block->phys >> 12].head = lowest;
|
||||
else
|
||||
{
|
||||
if (parent->left == block)
|
||||
parent->left = lowest;
|
||||
if (parent->right == block)
|
||||
parent->right = lowest;
|
||||
}
|
||||
lowest->parent = parent;
|
||||
|
||||
if (old_parent = block)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*Replace old lowest node with deleted node, and loop*/
|
||||
if (old_parent->left == lowest)
|
||||
old_parent->left = block->left;
|
||||
if (old_parent->right == lowest)
|
||||
old_parent->right = block->right;
|
||||
block->parent = old_parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define PAGE_MASK_MASK 63
|
||||
#define PAGE_MASK_SHIFT 6
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ static void delete_block(codeblock_t *block)
|
|||
fatal("Deleting deleted block\n");
|
||||
block->pc = 0;
|
||||
|
||||
codeblock_tree_delete(block);
|
||||
|
||||
if (block->prev)
|
||||
{
|
||||
block->prev->next = block->next;
|
||||
|
|
@ -425,6 +427,8 @@ void codegen_block_end()
|
|||
// pclog("End block %i\n", block_num);
|
||||
|
||||
recomp_page = -1;
|
||||
|
||||
codeblock_tree_add(block);
|
||||
}
|
||||
|
||||
void codegen_flush()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef _MEM_H_
|
||||
#define _MEM_H_
|
||||
|
||||
typedef struct mem_mapping_t
|
||||
{
|
||||
struct mem_mapping_t *prev, *next;
|
||||
|
|
@ -110,6 +113,9 @@ typedef struct page_t
|
|||
|
||||
struct codeblock_t *block, *block_2;
|
||||
|
||||
/*Head of codeblock tree associated with this page*/
|
||||
struct codeblock_t *head;
|
||||
|
||||
uint64_t code_present_mask, dirty_mask;
|
||||
} page_t;
|
||||
|
||||
|
|
@ -156,3 +162,5 @@ void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p);
|
|||
void mem_reset_page_blocks();
|
||||
|
||||
extern mem_mapping_t ram_low_mapping;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue