mirror of
https://github.com/libretro/pcsx2.git
synced 2025-02-24 03:22:47 +00:00
Patch by Firnis:
He wrote his own, faster replacement for std::vector and used it for the EE and IOP block managers. This cuts down compiling time for some blocks from nearly 1 second to ~ 0.1 - 0.3 seconds. With this shorter compiling time, audio and framerate should be more stable when changing levels in a game, for example. Thanks a bunch, Firnis ;) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4572 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
0f3f204ba7
commit
cfe376491e
@ -19,31 +19,11 @@
|
||||
|
||||
BASEBLOCKEX* BaseBlocks::New(u32 startpc, uptr fnptr)
|
||||
{
|
||||
BASEBLOCKEX newblock;
|
||||
std::vector<BASEBLOCKEX>::iterator iter;
|
||||
memset(&newblock, 0, sizeof newblock);
|
||||
newblock.startpc = startpc;
|
||||
newblock.fnptr = fnptr;
|
||||
|
||||
int imin = 0, imax = blocks.size(), imid;
|
||||
|
||||
while (imin < imax) {
|
||||
imid = (imin+imax)>>1;
|
||||
|
||||
if (blocks[imid].startpc > startpc)
|
||||
imax = imid;
|
||||
else
|
||||
imin = imid + 1;
|
||||
}
|
||||
|
||||
pxAssert(imin == blocks.size() || blocks[imin].startpc > startpc);
|
||||
iter = blocks.insert(blocks.begin() + imin, newblock);
|
||||
|
||||
std::pair<linkiter_t, linkiter_t> range = links.equal_range(startpc);
|
||||
for (linkiter_t i = range.first; i != range.second; ++i)
|
||||
*(u32*)i->second = fnptr - (i->second + 4);
|
||||
|
||||
return &*iter;
|
||||
|
||||
return blocks.insert(startpc, fnptr);;
|
||||
}
|
||||
|
||||
int BaseBlocks::LastIndex(u32 startpc) const
|
||||
|
@ -16,7 +16,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <map> // used by BaseBlockEx
|
||||
#include <utility>
|
||||
|
||||
// Every potential jump point in the PS2's addressable memory has a BASEBLOCK
|
||||
// associated with it. So that means a BASEBLOCK for every 4 bytes of PS2
|
||||
@ -44,6 +43,118 @@ struct BASEBLOCKEX
|
||||
|
||||
};
|
||||
|
||||
class BaseBlockArray {
|
||||
s32 _Reserved;
|
||||
s32 _Size;
|
||||
BASEBLOCKEX *blocks;
|
||||
|
||||
__fi void resize(s32 size)
|
||||
{
|
||||
pxAssert(size > 0);
|
||||
BASEBLOCKEX *newMem = new BASEBLOCKEX[size];
|
||||
if(blocks) {
|
||||
memmove(newMem, blocks, _Reserved * sizeof(BASEBLOCKEX));
|
||||
delete[] blocks;
|
||||
}
|
||||
blocks = newMem;
|
||||
pxAssert(blocks != NULL);
|
||||
}
|
||||
public:
|
||||
BaseBlockArray() : _Size(0),
|
||||
_Reserved(0)
|
||||
{
|
||||
}
|
||||
|
||||
~BaseBlockArray()
|
||||
{
|
||||
if(blocks) {
|
||||
delete[] blocks;
|
||||
}
|
||||
}
|
||||
|
||||
BaseBlockArray (s32 size) : _Size(0),
|
||||
_Reserved(0)
|
||||
{
|
||||
if(size > 0) {
|
||||
resize(size);
|
||||
}
|
||||
_Reserved = size;
|
||||
}
|
||||
|
||||
BASEBLOCKEX *insert(u32 startpc, uptr fnptr)
|
||||
{
|
||||
if(_Size + 1 >= _Reserved) {
|
||||
resize(_Reserved + 0x2000);
|
||||
_Reserved += 0x2000; // some games requires even more!
|
||||
}
|
||||
|
||||
int imin = 0, imax = _Size, imid;
|
||||
|
||||
while (imin < imax) {
|
||||
imid = (imin+imax)>>1;
|
||||
|
||||
if (blocks[imid].startpc > startpc)
|
||||
imax = imid;
|
||||
else
|
||||
imin = imid + 1;
|
||||
}
|
||||
|
||||
pxAssert(imin == _Size || blocks[imin].startpc > startpc);
|
||||
|
||||
if(imin < _Size) {
|
||||
// make a hole for a new block.
|
||||
memmove(blocks + imin + 1, blocks + imin, (_Size - imin) * sizeof(BASEBLOCKEX));
|
||||
}
|
||||
|
||||
memset((blocks + imin), 0, sizeof(BASEBLOCKEX));
|
||||
blocks[imin].startpc = startpc;
|
||||
blocks[imin].fnptr = fnptr;
|
||||
|
||||
_Size++;
|
||||
return &blocks[imin];
|
||||
}
|
||||
|
||||
void reserve(u32 size)
|
||||
{
|
||||
resize(size);
|
||||
_Reserved = size;
|
||||
}
|
||||
|
||||
__fi BASEBLOCKEX &operator[](int idx) const
|
||||
{
|
||||
return *(blocks + idx);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if(blocks) {
|
||||
memset(blocks, 0, sizeof(blocks));
|
||||
}
|
||||
_Size = 0;
|
||||
}
|
||||
|
||||
__fi u32 size() const
|
||||
{
|
||||
return _Size;
|
||||
}
|
||||
|
||||
__fi void erase(s32 first)
|
||||
{
|
||||
return erase(first, first + 1);
|
||||
}
|
||||
|
||||
__fi void erase(s32 first, s32 last)
|
||||
{
|
||||
int range = last - first;
|
||||
|
||||
if(last < _Size) {
|
||||
memmove(blocks + first, blocks + last, (_Size - last) * sizeof(BASEBLOCKEX));
|
||||
}
|
||||
|
||||
_Size -= range;
|
||||
}
|
||||
};
|
||||
|
||||
class BaseBlocks
|
||||
{
|
||||
protected:
|
||||
@ -52,7 +163,7 @@ protected:
|
||||
// switch to a hash map later?
|
||||
std::multimap<u32, uptr> links;
|
||||
uptr recompiler;
|
||||
std::vector<BASEBLOCKEX> blocks;
|
||||
BaseBlockArray blocks;
|
||||
|
||||
public:
|
||||
BaseBlocks() :
|
||||
@ -81,6 +192,7 @@ public:
|
||||
__fi int Index (u32 startpc) const
|
||||
{
|
||||
int idx = LastIndex(startpc);
|
||||
|
||||
if ((idx == -1) || (startpc < blocks[idx].startpc) ||
|
||||
((blocks[idx].size) && (startpc >= blocks[idx].startpc + blocks[idx].size * 4)))
|
||||
return -1;
|
||||
@ -92,6 +204,7 @@ public:
|
||||
{
|
||||
if (idx < 0 || idx >= (int)blocks.size())
|
||||
return 0;
|
||||
|
||||
return &blocks[idx];
|
||||
}
|
||||
|
||||
@ -100,26 +213,33 @@ public:
|
||||
return (*this)[Index(startpc)];
|
||||
}
|
||||
|
||||
__fi void Remove(int idx)
|
||||
__fi void Remove(int first, int last)
|
||||
{
|
||||
//u32 startpc = blocks[idx].startpc;
|
||||
std::pair<linkiter_t, linkiter_t> range = links.equal_range(blocks[idx].startpc);
|
||||
for (linkiter_t i = range.first; i != range.second; ++i)
|
||||
*(u32*)i->second = recompiler - (i->second + 4);
|
||||
pxAssert(first <= last);
|
||||
int idx = first;
|
||||
do{
|
||||
pxAssert(idx <= last);
|
||||
|
||||
if( IsDevBuild )
|
||||
{
|
||||
// Clear the first instruction to 0xcc (breakpoint), as a way to assert if some
|
||||
// static jumps get left behind to this block. Note: Do not clear more than the
|
||||
// first byte, since this code is called during exception handlers and event handlers
|
||||
// both of which expect to be able to return to the recompiled code.
|
||||
//u32 startpc = blocks[idx].startpc;
|
||||
std::pair<linkiter_t, linkiter_t> range = links.equal_range(blocks[idx].startpc);
|
||||
for (linkiter_t i = range.first; i != range.second; ++i)
|
||||
*(u32*)i->second = recompiler - (i->second + 4);
|
||||
|
||||
BASEBLOCKEX effu( blocks[idx] );
|
||||
memset( (void*)effu.fnptr, 0xcc, 1 );
|
||||
if( IsDevBuild )
|
||||
{
|
||||
// Clear the first instruction to 0xcc (breakpoint), as a way to assert if some
|
||||
// static jumps get left behind to this block. Note: Do not clear more than the
|
||||
// first byte, since this code is called during exception handlers and event handlers
|
||||
// both of which expect to be able to return to the recompiled code.
|
||||
|
||||
BASEBLOCKEX effu( blocks[idx] );
|
||||
memset( (void*)effu.fnptr, 0xcc, 1 );
|
||||
}
|
||||
}
|
||||
while(idx++ < last);
|
||||
|
||||
// TODO: remove links from this block?
|
||||
blocks.erase(blocks.begin() + idx);
|
||||
blocks.erase(first, last + 1);
|
||||
}
|
||||
|
||||
void Link(u32 pc, s32* jumpptr);
|
||||
|
@ -927,7 +927,6 @@ static __fi u32 psxRecClearMem(u32 pc)
|
||||
|
||||
u32 lowerextent = pc, upperextent = pc + 4;
|
||||
int blockidx = recBlocks.Index(pc);
|
||||
|
||||
pxAssert(blockidx != -1);
|
||||
|
||||
while (BASEBLOCKEX* pexblock = recBlocks[blockidx - 1]) {
|
||||
@ -938,13 +937,20 @@ static __fi u32 psxRecClearMem(u32 pc)
|
||||
blockidx--;
|
||||
}
|
||||
|
||||
int toRemoveFirst = blockidx;
|
||||
|
||||
while (BASEBLOCKEX* pexblock = recBlocks[blockidx]) {
|
||||
if (pexblock->startpc >= upperextent)
|
||||
break;
|
||||
|
||||
lowerextent = min(lowerextent, pexblock->startpc);
|
||||
upperextent = max(upperextent, pexblock->startpc + pexblock->size * 4);
|
||||
recBlocks.Remove(blockidx);
|
||||
|
||||
blockidx++;
|
||||
}
|
||||
|
||||
if(toRemoveFirst != blockidx) {
|
||||
recBlocks.Remove(toRemoveFirst, (blockidx - 1));
|
||||
}
|
||||
|
||||
blockidx=0;
|
||||
@ -1224,6 +1230,7 @@ static void __fastcall iopRecRecompile( const u32 startpc )
|
||||
|| s_pCurBlock->GetFnptr() == (uptr)iopJITCompileInBlock);
|
||||
|
||||
s_pCurBlockEx = recBlocks.Get(HWADDR(startpc));
|
||||
|
||||
if(!s_pCurBlockEx || s_pCurBlockEx->startpc != HWADDR(startpc))
|
||||
s_pCurBlockEx = recBlocks.New(HWADDR(startpc), (uptr)recPtr);
|
||||
|
||||
|
@ -889,13 +889,18 @@ void recClear(u32 addr, u32 size)
|
||||
if (pexblock)
|
||||
ceiling = pexblock->startpc;
|
||||
|
||||
int toRemoveLast = blockidx;
|
||||
|
||||
while (pexblock = recBlocks[blockidx]) {
|
||||
u32 blockstart = pexblock->startpc;
|
||||
u32 blockend = pexblock->startpc + pexblock->size * 4;
|
||||
BASEBLOCK* pblock = PC_GETBLOCK(blockstart);
|
||||
|
||||
if (pblock == s_pCurBlock) {
|
||||
blockidx--;
|
||||
if(toRemoveLast != blockidx) {
|
||||
recBlocks.Remove((blockidx + 1), toRemoveLast);
|
||||
}
|
||||
toRemoveLast = --blockidx;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -909,7 +914,12 @@ void recClear(u32 addr, u32 size)
|
||||
// This might end up inside a block that doesn't contain the clearing range,
|
||||
// so set it to recompile now. This will become JITCompile if we clear it.
|
||||
pblock->SetFnptr((uptr)JITCompileInBlock);
|
||||
recBlocks.Remove(blockidx--);
|
||||
|
||||
blockidx--;
|
||||
}
|
||||
|
||||
if(toRemoveLast != blockidx) {
|
||||
recBlocks.Remove((blockidx + 1), toRemoveLast);
|
||||
}
|
||||
|
||||
upperextent = min(upperextent, ceiling);
|
||||
|
Loading…
x
Reference in New Issue
Block a user