mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-25 15:19:42 -06:00
Remove global state from PPCAnalyst.cpp. Little bit of cleanup.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1580 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -45,7 +45,6 @@ namespace HW
|
|||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
CoreTiming::Init();
|
CoreTiming::Init();
|
||||||
PPCAnalyst::Init();
|
|
||||||
|
|
||||||
Thunk_Init(); // not really hw, but this way we know it's inited early :P
|
Thunk_Init(); // not really hw, but this way we know it's inited early :P
|
||||||
State_Init();
|
State_Init();
|
||||||
@ -91,7 +90,6 @@ namespace HW
|
|||||||
State_Shutdown();
|
State_Shutdown();
|
||||||
Thunk_Shutdown();
|
Thunk_Shutdown();
|
||||||
CoreTiming::Shutdown();
|
CoreTiming::Shutdown();
|
||||||
PPCAnalyst::Shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
|
@ -172,6 +172,7 @@ namespace Jit64
|
|||||||
{
|
{
|
||||||
JitState js;
|
JitState js;
|
||||||
JitOptions jo;
|
JitOptions jo;
|
||||||
|
PPCAnalyst::CodeBuffer code_buffer(32000);
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
@ -319,7 +320,10 @@ namespace Jit64
|
|||||||
|
|
||||||
//Analyze the block, collect all instructions it is made of (including inlining,
|
//Analyze the block, collect all instructions it is made of (including inlining,
|
||||||
//if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
|
//if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
|
||||||
PPCAnalyst::CodeOp *ops = PPCAnalyst::Flatten(emaddress, size, js.st, js.gpa, js.fpa);
|
|
||||||
|
PPCAnalyst::Flatten(emaddress, &size, &js.st, &js.gpa, &js.fpa, &code_buffer);
|
||||||
|
PPCAnalyst::CodeOp *ops = code_buffer.codebuffer;
|
||||||
|
|
||||||
const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr
|
const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr
|
||||||
b.checkedEntry = start;
|
b.checkedEntry = start;
|
||||||
b.runCount = 0;
|
b.runCount = 0;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
// dependency is a little inconvenient and this is possibly a slight
|
// dependency is a little inconvenient and this is possibly a slight
|
||||||
// performance hit, it's not enabled by default, but it's useful for
|
// performance hit, it's not enabled by default, but it's useful for
|
||||||
// locating performance issues.
|
// locating performance issues.
|
||||||
|
|
||||||
//#define OPROFILE_REPORT
|
//#define OPROFILE_REPORT
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -71,10 +72,10 @@ namespace Jit64
|
|||||||
TRAMPOLINE_SIZE = 1024*1024,
|
TRAMPOLINE_SIZE = 1024*1024,
|
||||||
//MAX_NUM_BLOCKS = 65536,
|
//MAX_NUM_BLOCKS = 65536,
|
||||||
};
|
};
|
||||||
int CODE_SIZE = 1024*1024*16; // nonconstant to be able to have an option for it
|
int CODE_SIZE = 1024*1024*16;
|
||||||
int MAX_NUM_BLOCKS = 65536*2;
|
int MAX_NUM_BLOCKS = 65536*2;
|
||||||
|
|
||||||
static u8 **blockCodePointers; // cut these in half and force below 2GB?
|
static u8 **blockCodePointers;
|
||||||
|
|
||||||
static std::multimap<u32, int> links_to;
|
static std::multimap<u32, int> links_to;
|
||||||
|
|
||||||
@ -133,8 +134,8 @@ namespace Jit64
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
|
// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
|
||||||
is full and when saving and loading states */
|
// is full and when saving and loading states.
|
||||||
void ClearCache()
|
void ClearCache()
|
||||||
{
|
{
|
||||||
Core::DisplayMessage("Cleared code cache.", 3000);
|
Core::DisplayMessage("Cleared code cache.", 3000);
|
||||||
@ -348,13 +349,6 @@ namespace Jit64
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if ((b.exitAddress[0] == INVALID_EXIT || b.linkStatus[0]) &&
|
|
||||||
(b.exitAddress[1] == INVALID_EXIT || b.linkStatus[1])) {
|
|
||||||
unlinked.erase(iter);
|
|
||||||
if (unlinked.size() > 4000) PanicAlert("Removed from unlinked. Size = %i", unlinked.size());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
void LinkBlock(int i)
|
void LinkBlock(int i)
|
||||||
{
|
{
|
||||||
@ -408,7 +402,6 @@ namespace Jit64
|
|||||||
SetCodePtr(prev_code); // reset code pointer
|
SetCodePtr(prev_code); // reset code pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BLR_OP 0x4e800020
|
|
||||||
|
|
||||||
void InvalidateCodeRange(u32 address, u32 length)
|
void InvalidateCodeRange(u32 address, u32 length)
|
||||||
{
|
{
|
||||||
@ -418,7 +411,7 @@ namespace Jit64
|
|||||||
//This is slow but should be safe (zelda needs it for block linking)
|
//This is slow but should be safe (zelda needs it for block linking)
|
||||||
for (int i = 0; i < numBlocks; i++)
|
for (int i = 0; i < numBlocks; i++)
|
||||||
{
|
{
|
||||||
if (RangeIntersect(blocks[i].originalAddress, blocks[i].originalAddress+blocks[i].originalSize,
|
if (RangeIntersect(blocks[i].originalAddress, blocks[i].originalAddress + blocks[i].originalSize,
|
||||||
address, address + length))
|
address, address + length))
|
||||||
{
|
{
|
||||||
DestroyBlock(i, true);
|
DestroyBlock(i, true);
|
||||||
|
@ -278,6 +278,10 @@ void stfs(UGeckoInstruction inst)
|
|||||||
|
|
||||||
void stfsx(UGeckoInstruction inst)
|
void stfsx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
|
#ifdef JIT_OFF_OPTIONS
|
||||||
|
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITLoadStoreFloatingOff)
|
||||||
|
{Default(inst); return;} // turn off from debugger
|
||||||
|
#endif
|
||||||
// We can take a shortcut here - it's not likely that a hardware access would use this instruction.
|
// We can take a shortcut here - it's not likely that a hardware access would use this instruction.
|
||||||
INSTRUCTION_START;
|
INSTRUCTION_START;
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
|
@ -182,7 +182,7 @@ void psq_st(UGeckoInstruction inst)
|
|||||||
{
|
{
|
||||||
if (gpr.R(a).IsImm() && !update && cpu_info.bSSSE3)
|
if (gpr.R(a).IsImm() && !update && cpu_info.bSSSE3)
|
||||||
{
|
{
|
||||||
u32 addr = gpr.R(a).offset + offset;
|
u32 addr = (u32)(gpr.R(a).offset + offset);
|
||||||
if (addr == 0xCC008000) {
|
if (addr == 0xCC008000) {
|
||||||
// Writing to FIFO. Let's do fast method.
|
// Writing to FIFO. Let's do fast method.
|
||||||
CVTPD2PS(XMM0, fpr.R(s));
|
CVTPD2PS(XMM0, fpr.R(s));
|
||||||
|
@ -40,30 +40,24 @@ namespace PPCAnalyst {
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
PPCAnalyst::CodeOp *codebuffer;
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
CODEBUFFER_SIZE = 32000,
|
CODEBUFFER_SIZE = 32000,
|
||||||
};
|
};
|
||||||
|
|
||||||
void Init()
|
CodeBuffer::CodeBuffer(int size)
|
||||||
{
|
{
|
||||||
codebuffer = new PPCAnalyst::CodeOp[CODEBUFFER_SIZE];
|
codebuffer = new PPCAnalyst::CodeOp[size];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
CodeBuffer::~CodeBuffer()
|
||||||
{
|
{
|
||||||
delete [] codebuffer;
|
delete [] codebuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AnalyzeFunction2(Symbol &func);
|
void AnalyzeFunction2(Symbol &func);
|
||||||
u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc);
|
u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc);
|
||||||
|
|
||||||
// void FixUpInternalBranches(CodeOp *code, int begin, int end);
|
|
||||||
|
|
||||||
|
|
||||||
#define INVALID_TARGET ((u32)-1)
|
#define INVALID_TARGET ((u32)-1)
|
||||||
|
|
||||||
u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc)
|
u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc)
|
||||||
@ -206,34 +200,14 @@ bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size)
|
|||||||
|
|
||||||
// Second pass analysis, done after the first pass is done for all functions
|
// Second pass analysis, done after the first pass is done for all functions
|
||||||
// so we have more information to work with
|
// so we have more information to work with
|
||||||
void AnalyzeFunction2(Symbol &func)
|
void AnalyzeFunction2(Symbol *func)
|
||||||
{
|
{
|
||||||
// u32 addr = func.address;
|
u32 flags = func->flags;
|
||||||
u32 flags = func.flags;
|
|
||||||
/*
|
|
||||||
for (int i = 0; i < func.size; i++)
|
|
||||||
{
|
|
||||||
UGeckoInstruction instr = (UGeckoInstruction)Memory::ReadUnchecked_U32(addr);
|
|
||||||
|
|
||||||
GekkoOPInfo *info = GetOpInfo(instr);
|
|
||||||
if (!info)
|
|
||||||
{
|
|
||||||
LOG(HLE,"Seems function %s contains bad op %08x",func.name,instr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (info->flags & FL_TIMER)
|
|
||||||
{
|
|
||||||
flags |= FFLAG_TIMERINSTRUCTIONS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addr+=4;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
bool nonleafcall = false;
|
bool nonleafcall = false;
|
||||||
for (size_t i = 0; i < func.calls.size(); i++)
|
for (size_t i = 0; i < func->calls.size(); i++)
|
||||||
{
|
{
|
||||||
SCall c = func.calls[i];
|
SCall c = func->calls[i];
|
||||||
Symbol *called_func = g_symbolDB.GetSymbolFromAddr(c.function);
|
Symbol *called_func = g_symbolDB.GetSymbolFromAddr(c.function);
|
||||||
if (called_func && (called_func->flags & FFLAG_LEAF) == 0)
|
if (called_func && (called_func->flags & FFLAG_LEAF) == 0)
|
||||||
{
|
{
|
||||||
@ -245,44 +219,7 @@ void AnalyzeFunction2(Symbol &func)
|
|||||||
if (nonleafcall && !(flags & FFLAG_EVIL) && !(flags & FFLAG_RFI))
|
if (nonleafcall && !(flags & FFLAG_EVIL) && !(flags & FFLAG_RFI))
|
||||||
flags |= FFLAG_ONLYCALLSNICELEAFS;
|
flags |= FFLAG_ONLYCALLSNICELEAFS;
|
||||||
|
|
||||||
func.flags = flags;
|
func->flags = flags;
|
||||||
}
|
|
||||||
|
|
||||||
// Currently not used
|
|
||||||
void FixUpInternalBranches(CodeOp *code, int begin, int end)
|
|
||||||
{
|
|
||||||
for (int i = begin; i < end; i++)
|
|
||||||
{
|
|
||||||
if (code[i].branchTo != INVALID_TARGET) //check if this branch already processed
|
|
||||||
{
|
|
||||||
if (code[i].inst.OPCD == 16)
|
|
||||||
{
|
|
||||||
u32 target = SignExt16(code[i].inst.BD<<2);
|
|
||||||
if (!code[i].inst.AA)
|
|
||||||
target += code[i].address;
|
|
||||||
//local branch
|
|
||||||
code[i].branchTo = target;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
code[i].branchTo = INVALID_TARGET;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//brute force
|
|
||||||
for (int i = begin; i < end; i++)
|
|
||||||
{
|
|
||||||
if (code[i].branchTo != INVALID_TARGET)
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (int j = begin; j < end; j++)
|
|
||||||
if (code[i].branchTo == code[j].address)
|
|
||||||
code[i].branchToIndex = j;
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
LOG(HLE, "ERROR: branch target missing");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMPORTANT - CURRENTLY ASSUMES THAT A IS A COMPARE
|
// IMPORTANT - CURRENTLY ASSUMES THAT A IS A COMPARE
|
||||||
@ -346,76 +283,40 @@ bool CanSwapAdjacentOps(const CodeOp &a, const CodeOp &b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Does not yet perform inlining - although there are plans for that.
|
// Does not yet perform inlining - although there are plans for that.
|
||||||
CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa, BlockRegStats &fpa)
|
void Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, BlockRegStats *fpa, CodeBuffer *buffer)
|
||||||
{
|
{
|
||||||
int numCycles = 0;
|
int numCycles = 0;
|
||||||
u32 blockstart = address;
|
u32 blockstart = address;
|
||||||
memset(&st, 0, sizeof(st));
|
memset(st, 0, sizeof(st));
|
||||||
UGeckoInstruction previnst = Memory::Read_Instruction(address-4);
|
UGeckoInstruction previnst = Memory::Read_Instruction(address - 4);
|
||||||
if (previnst.hex == 0x4e800020)
|
if (previnst.hex == 0x4e800020)
|
||||||
{
|
{
|
||||||
st.isFirstBlockOfFunction = true;
|
st->isFirstBlockOfFunction = true;
|
||||||
}
|
}
|
||||||
|
gpa->any = true;
|
||||||
|
fpa->any = false;
|
||||||
|
|
||||||
gpa.any = true;
|
|
||||||
fpa.any = false;
|
|
||||||
|
|
||||||
enum Todo
|
|
||||||
{
|
|
||||||
JustCopy = 0, Flatten = 1, Nothing = 2
|
|
||||||
};
|
|
||||||
Todo todo = Nothing;
|
|
||||||
|
|
||||||
//Symbol *f = g_symbolDB.GetSymbolFromAddr(address);
|
|
||||||
int maxsize = CODEBUFFER_SIZE;
|
int maxsize = CODEBUFFER_SIZE;
|
||||||
//for now, all will return JustCopy :P
|
int num_inst = 0;
|
||||||
/*
|
|
||||||
if (f)
|
|
||||||
{
|
|
||||||
if (f->flags & FFLAG_LEAF)
|
|
||||||
{
|
|
||||||
//no reason to flatten
|
|
||||||
todo = JustCopy;
|
|
||||||
}
|
|
||||||
else if (f->flags & FFLAG_ONLYCALLSNICELEAFS)
|
|
||||||
{
|
|
||||||
//inline calls if possible
|
|
||||||
//todo = Flatten;
|
|
||||||
todo = JustCopy;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
todo = JustCopy;
|
|
||||||
}
|
|
||||||
todo = JustCopy;
|
|
||||||
|
|
||||||
maxsize = f->size;
|
|
||||||
}
|
|
||||||
else*/
|
|
||||||
todo = JustCopy;
|
|
||||||
|
|
||||||
CodeOp *code = codebuffer; //new CodeOp[size];
|
|
||||||
|
|
||||||
if (todo == JustCopy)
|
|
||||||
{
|
|
||||||
realsize = 0;
|
|
||||||
bool foundExit = false;
|
|
||||||
int numFollows = 0;
|
int numFollows = 0;
|
||||||
for (int i = 0; i < maxsize; i++, realsize++)
|
|
||||||
|
CodeOp *code = buffer->codebuffer;
|
||||||
|
bool foundExit = false;
|
||||||
|
|
||||||
|
// Flatten! (Currently just copies, following branches is disabled)
|
||||||
|
for (int i = 0; i < maxsize; i++, num_inst++)
|
||||||
{
|
{
|
||||||
memset(&code[i], 0, sizeof(CodeOp));
|
memset(&code[i], 0, sizeof(CodeOp));
|
||||||
code[i].address = address;
|
code[i].address = address;
|
||||||
UGeckoInstruction inst = Memory::Read_Instruction(code[i].address);
|
UGeckoInstruction inst = Memory::Read_Instruction(code[i].address);
|
||||||
_assert_msg_(GEKKO, inst.hex != 0, "Zero Op - Error flattening %08x op %08x",address+i*4,inst);
|
_assert_msg_(GEKKO, inst.hex != 0, "Zero Op - Error flattening %08x op %08x", address + i*4, inst);
|
||||||
code[i].inst = inst;
|
code[i].inst = inst;
|
||||||
code[i].branchTo = -1;
|
code[i].branchTo = -1;
|
||||||
code[i].branchToIndex = -1;
|
code[i].branchToIndex = -1;
|
||||||
GekkoOPInfo *opinfo = GetOpInfo(inst);
|
GekkoOPInfo *opinfo = GetOpInfo(inst);
|
||||||
if (opinfo)
|
if (opinfo)
|
||||||
numCycles += opinfo->numCyclesMinusOne + 1;
|
numCycles += opinfo->numCyclesMinusOne + 1;
|
||||||
_assert_msg_(GEKKO, opinfo != 0, "Invalid Op - Error flattening %08x op %08x",address+i*4,inst);
|
_assert_msg_(GEKKO, opinfo != 0, "Invalid Op - Error flattening %08x op %08x", address + i*4, inst);
|
||||||
int flags = opinfo->flags;
|
|
||||||
|
|
||||||
bool follow = false;
|
bool follow = false;
|
||||||
u32 destination;
|
u32 destination;
|
||||||
if (inst.OPCD == 18)
|
if (inst.OPCD == 18)
|
||||||
@ -432,11 +333,10 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
|||||||
numFollows++;
|
numFollows++;
|
||||||
if (numFollows > 1)
|
if (numFollows > 1)
|
||||||
follow = false;
|
follow = false;
|
||||||
|
|
||||||
follow = false;
|
follow = false;
|
||||||
if (!follow)
|
if (!follow)
|
||||||
{
|
{
|
||||||
if (flags & FL_ENDBLOCK) //right now we stop early
|
if (opinfo->flags & FL_ENDBLOCK) //right now we stop early
|
||||||
{
|
{
|
||||||
foundExit = true;
|
foundExit = true;
|
||||||
break;
|
break;
|
||||||
@ -448,36 +348,27 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
|||||||
address = destination;
|
address = destination;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_assert_msg_(GEKKO,foundExit,"Analyzer ERROR - Function %08x too big", blockstart);
|
|
||||||
realsize++;
|
_assert_msg_(GEKKO, foundExit, "Analyzer ERROR - Function %08x too big", blockstart);
|
||||||
st.numCycles = numCycles;
|
num_inst++; // why?
|
||||||
FixUpInternalBranches(code,0,realsize);
|
st->numCycles = numCycles;
|
||||||
}
|
|
||||||
else if (todo == Flatten)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do analysis of the code, look for dependencies etc
|
// Do analysis of the code, look for dependencies etc
|
||||||
int numSystemInstructions = 0;
|
int numSystemInstructions = 0;
|
||||||
for (int i = 0; i < 32; i++)
|
for (int i = 0; i < 32; i++)
|
||||||
{
|
{
|
||||||
gpa.firstRead[i] = -1;
|
gpa->firstRead[i] = -1;
|
||||||
gpa.firstWrite[i] = -1;
|
gpa->firstWrite[i] = -1;
|
||||||
gpa.numReads[i] = 0;
|
gpa->numReads[i] = 0;
|
||||||
gpa.numWrites[i] = 0;
|
gpa->numWrites[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpa.any = true;
|
gpa->any = true;
|
||||||
for (size_t i = 0; i < realsize; i++)
|
for (size_t i = 0; i < num_inst; i++)
|
||||||
{
|
{
|
||||||
UGeckoInstruction inst = code[i].inst;
|
UGeckoInstruction inst = code[i].inst;
|
||||||
if (PPCTables::UsesFPU(inst))
|
if (PPCTables::UsesFPU(inst))
|
||||||
fpa.any = true;
|
fpa->any = true;
|
||||||
|
|
||||||
code[i].wantsCR0 = false;
|
code[i].wantsCR0 = false;
|
||||||
code[i].wantsCR1 = false;
|
code[i].wantsCR1 = false;
|
||||||
@ -488,7 +379,7 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
|||||||
int flags = opinfo->flags;
|
int flags = opinfo->flags;
|
||||||
|
|
||||||
if (flags & FL_TIMER)
|
if (flags & FL_TIMER)
|
||||||
gpa.anyTimer = true;
|
gpa->anyTimer = true;
|
||||||
|
|
||||||
// Does the instruction output CR0?
|
// Does the instruction output CR0?
|
||||||
if (flags & FL_RC_BIT)
|
if (flags & FL_RC_BIT)
|
||||||
@ -521,37 +412,37 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
|||||||
if (flags & FL_OUT_A)
|
if (flags & FL_OUT_A)
|
||||||
{
|
{
|
||||||
code[i].regsOut[numOut++] = inst.RA;
|
code[i].regsOut[numOut++] = inst.RA;
|
||||||
gpa.numWrites[inst.RA]++;
|
gpa->numWrites[inst.RA]++;
|
||||||
}
|
}
|
||||||
if (flags & FL_OUT_D)
|
if (flags & FL_OUT_D)
|
||||||
{
|
{
|
||||||
code[i].regsOut[numOut++] = inst.RD;
|
code[i].regsOut[numOut++] = inst.RD;
|
||||||
gpa.numWrites[inst.RD]++;
|
gpa->numWrites[inst.RD]++;
|
||||||
}
|
}
|
||||||
if (flags & FL_OUT_S)
|
if (flags & FL_OUT_S)
|
||||||
{
|
{
|
||||||
code[i].regsOut[numOut++] = inst.RS;
|
code[i].regsOut[numOut++] = inst.RS;
|
||||||
gpa.numWrites[inst.RS]++;
|
gpa->numWrites[inst.RS]++;
|
||||||
}
|
}
|
||||||
if ((flags & FL_IN_A) || ((flags & FL_IN_A0) && inst.RA != 0))
|
if ((flags & FL_IN_A) || ((flags & FL_IN_A0) && inst.RA != 0))
|
||||||
{
|
{
|
||||||
code[i].regsIn[numIn++] = inst.RA;
|
code[i].regsIn[numIn++] = inst.RA;
|
||||||
gpa.numReads[inst.RA]++;
|
gpa->numReads[inst.RA]++;
|
||||||
}
|
}
|
||||||
if (flags & FL_IN_B)
|
if (flags & FL_IN_B)
|
||||||
{
|
{
|
||||||
code[i].regsIn[numIn++] = inst.RB;
|
code[i].regsIn[numIn++] = inst.RB;
|
||||||
gpa.numReads[inst.RB]++;
|
gpa->numReads[inst.RB]++;
|
||||||
}
|
}
|
||||||
if (flags & FL_IN_C)
|
if (flags & FL_IN_C)
|
||||||
{
|
{
|
||||||
code[i].regsIn[numIn++] = inst.RC;
|
code[i].regsIn[numIn++] = inst.RC;
|
||||||
gpa.numReads[inst.RC]++;
|
gpa->numReads[inst.RC]++;
|
||||||
}
|
}
|
||||||
if (flags & FL_IN_S)
|
if (flags & FL_IN_S)
|
||||||
{
|
{
|
||||||
code[i].regsIn[numIn++] = inst.RS;
|
code[i].regsIn[numIn++] = inst.RS;
|
||||||
gpa.numReads[inst.RS]++;
|
gpa->numReads[inst.RS]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (opinfo->type)
|
switch (opinfo->type)
|
||||||
@ -583,10 +474,10 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
|||||||
int r = code[i].regsIn[j];
|
int r = code[i].regsIn[j];
|
||||||
if (r < 0 || r > 31)
|
if (r < 0 || r > 31)
|
||||||
PanicAlert("wtf");
|
PanicAlert("wtf");
|
||||||
if (gpa.firstRead[r] == -1)
|
if (gpa->firstRead[r] == -1)
|
||||||
gpa.firstRead[r] = (short)(i);
|
gpa->firstRead[r] = (short)(i);
|
||||||
gpa.lastRead[r] = (short)(i);
|
gpa->lastRead[r] = (short)(i);
|
||||||
gpa.numReads[r]++;
|
gpa->numReads[r]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < numOut; j++)
|
for (int j = 0; j < numOut; j++)
|
||||||
@ -594,18 +485,18 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
|||||||
int r = code[i].regsOut[j];
|
int r = code[i].regsOut[j];
|
||||||
if (r < 0 || r > 31)
|
if (r < 0 || r > 31)
|
||||||
PanicAlert("wtf");
|
PanicAlert("wtf");
|
||||||
if (gpa.firstWrite[r] == -1)
|
if (gpa->firstWrite[r] == -1)
|
||||||
gpa.firstWrite[r] = (short)(i);
|
gpa->firstWrite[r] = (short)(i);
|
||||||
gpa.lastWrite[r] = (short)(i);
|
gpa->lastWrite[r] = (short)(i);
|
||||||
gpa.numWrites[r]++;
|
gpa->numWrites[r]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instruction Reordering Pass
|
// Instruction Reordering Pass
|
||||||
|
|
||||||
// Bubble down compares towards branches, so that they can be merged (merging not yet implemented).
|
// Bubble down compares towards branches, so that they can be merged.
|
||||||
// -2: -1 for the pair, -1 for not swapping with the final instruction which is probably the branch.
|
// -2: -1 for the pair, -1 for not swapping with the final instruction which is probably the branch.
|
||||||
for (int i = 0; i < (realsize - 2); i++)
|
for (int i = 0; i < num_inst - 2; i++)
|
||||||
{
|
{
|
||||||
CodeOp &a = code[i];
|
CodeOp &a = code[i];
|
||||||
CodeOp &b = code[i + 1];
|
CodeOp &b = code[i + 1];
|
||||||
@ -628,7 +519,7 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
|||||||
bool wantsCR0 = true;
|
bool wantsCR0 = true;
|
||||||
bool wantsCR1 = true;
|
bool wantsCR1 = true;
|
||||||
bool wantsPS1 = true;
|
bool wantsPS1 = true;
|
||||||
for (int i = realsize - 1; i; i--)
|
for (int i = num_inst - 1; i; i--)
|
||||||
{
|
{
|
||||||
if (code[i].outputCR0)
|
if (code[i].outputCR0)
|
||||||
wantsCR0 = false;
|
wantsCR0 = false;
|
||||||
@ -644,40 +535,11 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
|||||||
code[i].wantsPS1 = wantsPS1;
|
code[i].wantsPS1 = wantsPS1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time for code shuffling, taking into account the above dependency analysis.
|
*realsize = num_inst;
|
||||||
bool successful_shuffle = false;
|
// ...
|
||||||
//Move compares
|
|
||||||
// Try to push compares as close as possible to the following branch
|
|
||||||
// this way we can do neat stuff like combining compare and branch
|
|
||||||
// and avoid emitting any cr flags at all
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
pseudo:
|
|
||||||
if (op is cmp and sets CR0)
|
|
||||||
{
|
|
||||||
scan forward for branch
|
|
||||||
if we hit any instruction that sets CR0, bail
|
|
||||||
if we hit any instruction that writes to any of the cmp input variables, bail
|
|
||||||
shuffleup(code, cmpaddr, branchaddr-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
how to merge:
|
|
||||||
if (op is cmp and nextop is condbranch)
|
|
||||||
{
|
|
||||||
check if nextnextop wants cr
|
|
||||||
if it does, bail (or merge and write cr)
|
|
||||||
else merge!
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
if (successful_shuffle) {
|
|
||||||
// Disasm before and after, display side by side
|
|
||||||
}
|
|
||||||
// Decide what regs to potentially regcache
|
|
||||||
return code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Most functions that are relevant to analyze should be
|
// Most functions that are relevant to analyze should be
|
||||||
// called by another function. Therefore, let's scan the
|
// called by another function. Therefore, let's scan the
|
||||||
// entire space for bl operations and find what functions
|
// entire space for bl operations and find what functions
|
||||||
@ -759,9 +621,9 @@ void FindFunctions(u32 startAddr, u32 endAddr, SymbolDB *func_db)
|
|||||||
LOG(HLE, "weird function");
|
LOG(HLE, "weird function");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
AnalyzeFunction2(iter->second);
|
AnalyzeFunction2(&(iter->second));
|
||||||
Symbol &f = iter->second;
|
Symbol &f = iter->second;
|
||||||
if (f.name.substr(0,3) == "zzz")
|
if (f.name.substr(0, 3) == "zzz")
|
||||||
{
|
{
|
||||||
if (f.flags & FFLAG_LEAF)
|
if (f.flags & FFLAG_LEAF)
|
||||||
f.name += "_leaf";
|
f.name += "_leaf";
|
||||||
@ -810,46 +672,4 @@ void FindFunctions(u32 startAddr, u32 endAddr, SymbolDB *func_db)
|
|||||||
LOG(HLE, "Average size: %i (leaf), %i (nice), %i(unnice)", leafSize, niceSize, unniceSize);
|
LOG(HLE, "Average size: %i (leaf), %i (nice), %i(unnice)", leafSize, niceSize, unniceSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
void AnalyzeBackwards()
|
|
||||||
{
|
|
||||||
#ifndef BWLINKS
|
|
||||||
return;
|
|
||||||
#else
|
|
||||||
for (int i=0; i<numEntries; i++)
|
|
||||||
{
|
|
||||||
u32 ptr = entries[i].vaddress;
|
|
||||||
if (ptr && entries[i].type == ST_FUNCTION)
|
|
||||||
{
|
|
||||||
for (int a = 0; a<entries[i].size/4; a++)
|
|
||||||
{
|
|
||||||
u32 inst = Memory::ReadUnchecked_U32(ptr);
|
|
||||||
switch (inst >> 26)
|
|
||||||
{
|
|
||||||
case 18:
|
|
||||||
if (LK) //LK
|
|
||||||
{
|
|
||||||
u32 addr;
|
|
||||||
if(AA)
|
|
||||||
addr = SignExt26(LI << 2);
|
|
||||||
else
|
|
||||||
addr = ptr + SignExt26(LI << 2);
|
|
||||||
|
|
||||||
int funNum = GetSymbolNum(addr);
|
|
||||||
if (funNum>=0)
|
|
||||||
entries[funNum].backwardLinks.push_back(ptr);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
;
|
|
||||||
}
|
|
||||||
ptr+=4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -76,13 +76,20 @@ struct BlockRegStats
|
|||||||
min(firstRead[reg], firstWrite[reg]);}
|
min(firstRead[reg], firstWrite[reg]);}
|
||||||
};
|
};
|
||||||
|
|
||||||
void Init();
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa, BlockRegStats &fpa);
|
class CodeBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CodeBuffer(int size);
|
||||||
|
~CodeBuffer();
|
||||||
|
|
||||||
|
PPCAnalyst::CodeOp *codebuffer;
|
||||||
|
int size_;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, BlockRegStats *fpa, CodeBuffer *buffer);
|
||||||
|
|
||||||
void LogFunctionCall(u32 addr);
|
void LogFunctionCall(u32 addr);
|
||||||
|
|
||||||
void FindFunctions(u32 startAddr, u32 endAddr, SymbolDB *func_db);
|
void FindFunctions(u32 startAddr, u32 endAddr, SymbolDB *func_db);
|
||||||
bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size = 0);
|
bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size = 0);
|
||||||
|
|
||||||
|
@ -122,8 +122,7 @@ Interpreter::_interpreterInstruction GetInterpreterOp(UGeckoInstruction _inst)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GekkoOPTemplate primarytable[] =
|
||||||
GekkoOPTemplate primarytable[] =
|
|
||||||
{
|
{
|
||||||
{4, Interpreter::RunTable4, DynaRunTable4, {"RunTable4", OPTYPE_SUBTABLE | (4<<24), 0}},
|
{4, Interpreter::RunTable4, DynaRunTable4, {"RunTable4", OPTYPE_SUBTABLE | (4<<24), 0}},
|
||||||
{19, Interpreter::RunTable19, DynaRunTable19, {"RunTable19", OPTYPE_SUBTABLE | (19<<24), 0}},
|
{19, Interpreter::RunTable19, DynaRunTable19, {"RunTable19", OPTYPE_SUBTABLE | (19<<24), 0}},
|
||||||
@ -204,7 +203,7 @@ GekkoOPTemplate primarytable[] =
|
|||||||
{58, Interpreter::unknown_instruction, Jit64::Default, {"unknown_instruction", OPTYPE_UNKNOWN, 0}},
|
{58, Interpreter::unknown_instruction, Jit64::Default, {"unknown_instruction", OPTYPE_UNKNOWN, 0}},
|
||||||
};
|
};
|
||||||
|
|
||||||
GekkoOPTemplate table4[] =
|
static GekkoOPTemplate table4[] =
|
||||||
{ //SUBOP10
|
{ //SUBOP10
|
||||||
{0, Interpreter::ps_cmpu0, Jit64::Default, {"ps_cmpu0", OPTYPE_PS, FL_SET_CRn}},
|
{0, Interpreter::ps_cmpu0, Jit64::Default, {"ps_cmpu0", OPTYPE_PS, FL_SET_CRn}},
|
||||||
{32, Interpreter::ps_cmpo0, Jit64::Default, {"ps_cmpo0", OPTYPE_PS, FL_SET_CRn}},
|
{32, Interpreter::ps_cmpo0, Jit64::Default, {"ps_cmpo0", OPTYPE_PS, FL_SET_CRn}},
|
||||||
@ -222,7 +221,7 @@ GekkoOPTemplate table4[] =
|
|||||||
{1014, Interpreter::dcbz_l, Jit64::Default, {"dcbz_l", OPTYPE_SYSTEM, 0}},
|
{1014, Interpreter::dcbz_l, Jit64::Default, {"dcbz_l", OPTYPE_SYSTEM, 0}},
|
||||||
};
|
};
|
||||||
|
|
||||||
GekkoOPTemplate table4_2[] =
|
static GekkoOPTemplate table4_2[] =
|
||||||
{
|
{
|
||||||
{10, Interpreter::ps_sum0, Jit64::ps_sum, {"ps_sum0", OPTYPE_PS, 0}},
|
{10, Interpreter::ps_sum0, Jit64::ps_sum, {"ps_sum0", OPTYPE_PS, 0}},
|
||||||
{11, Interpreter::ps_sum1, Jit64::ps_sum, {"ps_sum1", OPTYPE_PS, 0}},
|
{11, Interpreter::ps_sum1, Jit64::ps_sum, {"ps_sum1", OPTYPE_PS, 0}},
|
||||||
@ -244,7 +243,7 @@ GekkoOPTemplate table4_2[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
GekkoOPTemplate table4_3[] =
|
static GekkoOPTemplate table4_3[] =
|
||||||
{
|
{
|
||||||
{6, Interpreter::psq_lx, Jit64::Default, {"psq_lx", OPTYPE_PS, 0}},
|
{6, Interpreter::psq_lx, Jit64::Default, {"psq_lx", OPTYPE_PS, 0}},
|
||||||
{7, Interpreter::psq_stx, Jit64::Default, {"psq_stx", OPTYPE_PS, 0}},
|
{7, Interpreter::psq_stx, Jit64::Default, {"psq_stx", OPTYPE_PS, 0}},
|
||||||
@ -252,7 +251,7 @@ GekkoOPTemplate table4_3[] =
|
|||||||
{39, Interpreter::psq_stux, Jit64::Default, {"psq_stux", OPTYPE_PS, 0}},
|
{39, Interpreter::psq_stux, Jit64::Default, {"psq_stux", OPTYPE_PS, 0}},
|
||||||
};
|
};
|
||||||
|
|
||||||
GekkoOPTemplate table19[] =
|
static GekkoOPTemplate table19[] =
|
||||||
{
|
{
|
||||||
{528, Interpreter::bcctrx, Jit64::bcctrx, {"bcctrx", OPTYPE_BRANCH, FL_ENDBLOCK}},
|
{528, Interpreter::bcctrx, Jit64::bcctrx, {"bcctrx", OPTYPE_BRANCH, FL_ENDBLOCK}},
|
||||||
{16, Interpreter::bclrx, Jit64::bclrx, {"bclrx", OPTYPE_BRANCH, FL_ENDBLOCK}},
|
{16, Interpreter::bclrx, Jit64::bclrx, {"bclrx", OPTYPE_BRANCH, FL_ENDBLOCK}},
|
||||||
@ -273,7 +272,7 @@ GekkoOPTemplate table19[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
GekkoOPTemplate table31[] =
|
static GekkoOPTemplate table31[] =
|
||||||
{
|
{
|
||||||
{28, Interpreter::andx, Jit64::andx, {"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
{28, Interpreter::andx, Jit64::andx, {"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||||
{60, Interpreter::andcx, Jit64::Default, {"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
{60, Interpreter::andcx, Jit64::Default, {"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||||
@ -386,7 +385,7 @@ GekkoOPTemplate table31[] =
|
|||||||
{566, Interpreter::tlbsync, Jit64::Default, {"tlbsync", OPTYPE_SYSTEM, 0}},
|
{566, Interpreter::tlbsync, Jit64::Default, {"tlbsync", OPTYPE_SYSTEM, 0}},
|
||||||
};
|
};
|
||||||
|
|
||||||
GekkoOPTemplate table31_2[] =
|
static GekkoOPTemplate table31_2[] =
|
||||||
{
|
{
|
||||||
{266, Interpreter::addx, Jit64::addx, {"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
{266, Interpreter::addx, Jit64::addx, {"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||||
{10, Interpreter::addcx, Jit64::Default, {"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
{10, Interpreter::addcx, Jit64::Default, {"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||||
@ -406,7 +405,7 @@ GekkoOPTemplate table31_2[] =
|
|||||||
{200, Interpreter::subfzex, Jit64::Default, {"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
{200, Interpreter::subfzex, Jit64::Default, {"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||||
};
|
};
|
||||||
|
|
||||||
GekkoOPTemplate table59[] =
|
static GekkoOPTemplate table59[] =
|
||||||
{
|
{
|
||||||
{18, Interpreter::fdivsx, Jit64::fp_arith_s, {"fdivsx", OPTYPE_FPU, FL_RC_BIT_F, 16}},
|
{18, Interpreter::fdivsx, Jit64::fp_arith_s, {"fdivsx", OPTYPE_FPU, FL_RC_BIT_F, 16}},
|
||||||
{20, Interpreter::fsubsx, Jit64::fp_arith_s, {"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
{20, Interpreter::fsubsx, Jit64::fp_arith_s, {"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
@ -420,7 +419,7 @@ GekkoOPTemplate table59[] =
|
|||||||
{31, Interpreter::fnmaddsx, Jit64::fmaddXX, {"fnmaddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
{31, Interpreter::fnmaddsx, Jit64::fmaddXX, {"fnmaddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
};
|
};
|
||||||
|
|
||||||
GekkoOPTemplate table63[] =
|
static GekkoOPTemplate table63[] =
|
||||||
{
|
{
|
||||||
{264, Interpreter::fabsx, Jit64::Default, {"fabsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
{264, Interpreter::fabsx, Jit64::Default, {"fabsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
{32, Interpreter::fcmpo, Jit64::fcmpx, {"fcmpo", OPTYPE_FPU, FL_RC_BIT_F}},
|
{32, Interpreter::fcmpo, Jit64::fcmpx, {"fcmpo", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
@ -440,7 +439,7 @@ GekkoOPTemplate table63[] =
|
|||||||
{711, Interpreter::mtfsfx, Jit64::Default, {"mtfsfx", OPTYPE_SYSTEMFP, 0, 2}},
|
{711, Interpreter::mtfsfx, Jit64::Default, {"mtfsfx", OPTYPE_SYSTEMFP, 0, 2}},
|
||||||
};
|
};
|
||||||
|
|
||||||
GekkoOPTemplate table63_2[] =
|
static GekkoOPTemplate table63_2[] =
|
||||||
{
|
{
|
||||||
{18, Interpreter::fdivx, Jit64::Default, {"fdivx", OPTYPE_FPU, FL_RC_BIT_F, 30}},
|
{18, Interpreter::fdivx, Jit64::Default, {"fdivx", OPTYPE_FPU, FL_RC_BIT_F, 30}},
|
||||||
{20, Interpreter::fsubx, Jit64::Default, {"fsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
{20, Interpreter::fsubx, Jit64::Default, {"fsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
@ -455,7 +454,10 @@ GekkoOPTemplate table63_2[] =
|
|||||||
{31, Interpreter::fnmaddx, Jit64::fmaddXX, {"fnmaddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
{31, Interpreter::fnmaddx, Jit64::fmaddXX, {"fnmaddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||||
};
|
};
|
||||||
|
|
||||||
bool PPCTables::UsesFPU(UGeckoInstruction _inst)
|
namespace PPCTables
|
||||||
|
{
|
||||||
|
|
||||||
|
bool UsesFPU(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
switch (_inst.OPCD)
|
switch (_inst.OPCD)
|
||||||
{
|
{
|
||||||
@ -500,7 +502,7 @@ bool PPCTables::UsesFPU(UGeckoInstruction _inst)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCTables::InitTables()
|
void InitTables()
|
||||||
{
|
{
|
||||||
//clear
|
//clear
|
||||||
for (int i = 0; i < 32; i++)
|
for (int i = 0; i < 32; i++)
|
||||||
@ -671,31 +673,30 @@ void PPCTables::CompileInstruction(UGeckoInstruction _inst)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PPCTables::IsValidInstruction(UGeckoInstruction _instCode)
|
bool IsValidInstruction(UGeckoInstruction _instCode)
|
||||||
{
|
{
|
||||||
const GekkoOPInfo *info = GetOpInfo(_instCode);
|
const GekkoOPInfo *info = GetOpInfo(_instCode);
|
||||||
return info != 0;
|
return info != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCTables::CountInstruction(UGeckoInstruction _inst)
|
void CountInstruction(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
GekkoOPInfo *info = GetOpInfo(_inst);
|
GekkoOPInfo *info = GetOpInfo(_inst);
|
||||||
if (info)
|
if (info)
|
||||||
info->runCount++;
|
info->runCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct inf
|
void PrintInstructionRunCounts()
|
||||||
{
|
{
|
||||||
|
struct inf
|
||||||
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
int count;
|
int count;
|
||||||
bool operator < (const inf &o) const
|
bool operator < (const inf &o) const
|
||||||
{
|
{
|
||||||
return count > o.count;
|
return count > o.count;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void PPCTables::PrintInstructionRunCounts()
|
|
||||||
{
|
|
||||||
std::vector<inf> temp;
|
std::vector<inf> temp;
|
||||||
for (int i = 0; i < m_numInstructions; i++)
|
for (int i = 0; i < m_numInstructions; i++)
|
||||||
{
|
{
|
||||||
@ -712,7 +713,7 @@ void PPCTables::PrintInstructionRunCounts()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO move to LogManager
|
//TODO move to LogManager
|
||||||
void PPCTables::LogCompiledInstructions()
|
void LogCompiledInstructions()
|
||||||
{
|
{
|
||||||
static int time = 0;
|
static int time = 0;
|
||||||
FILE *f = fopen(StringFromFormat(FULL_LOGS_DIR "inst_log%i.txt", time).c_str(), "w");
|
FILE *f = fopen(StringFromFormat(FULL_LOGS_DIR "inst_log%i.txt", time).c_str(), "w");
|
||||||
@ -740,3 +741,5 @@ void PPCTables::LogCompiledInstructions()
|
|||||||
#endif
|
#endif
|
||||||
time++;
|
time++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
@ -71,6 +71,18 @@ enum
|
|||||||
OPTYPE_UNKNOWN ,
|
OPTYPE_UNKNOWN ,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OPCD_HLEFUNCTION = 1,
|
||||||
|
OPCD_COMPILEDBLOCK = 2,
|
||||||
|
OPCD_BCx = 16,
|
||||||
|
OPCD_SC = 17,
|
||||||
|
OPCD_Bx = 18,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OP_BLR = 0x4e800020,
|
||||||
|
};
|
||||||
|
|
||||||
struct GekkoOPInfo
|
struct GekkoOPInfo
|
||||||
{
|
{
|
||||||
const char *opname;
|
const char *opname;
|
||||||
@ -85,21 +97,21 @@ struct GekkoOPInfo
|
|||||||
GekkoOPInfo *GetOpInfo(UGeckoInstruction _inst);
|
GekkoOPInfo *GetOpInfo(UGeckoInstruction _inst);
|
||||||
Interpreter::_interpreterInstruction GetInterpreterOp(UGeckoInstruction _inst);
|
Interpreter::_interpreterInstruction GetInterpreterOp(UGeckoInstruction _inst);
|
||||||
|
|
||||||
class PPCTables
|
namespace PPCTables
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
typedef void (*_recompilerInstruction) (UGeckoInstruction instCode);
|
|
||||||
typedef void (*_interpreterInstruction)(UGeckoInstruction instCode);
|
|
||||||
|
|
||||||
static void InitTables();
|
typedef void (*_recompilerInstruction) (UGeckoInstruction instCode);
|
||||||
static bool IsValidInstruction(UGeckoInstruction _instCode);
|
typedef void (*_interpreterInstruction)(UGeckoInstruction instCode);
|
||||||
static bool UsesFPU(UGeckoInstruction _inst);
|
|
||||||
|
|
||||||
static void CountInstruction(UGeckoInstruction _inst);
|
void InitTables();
|
||||||
static void PrintInstructionRunCounts();
|
bool IsValidInstruction(UGeckoInstruction _instCode);
|
||||||
static void LogCompiledInstructions();
|
bool UsesFPU(UGeckoInstruction _inst);
|
||||||
|
|
||||||
static void CompileInstruction(UGeckoInstruction _inst);
|
void CountInstruction(UGeckoInstruction _inst);
|
||||||
};
|
void PrintInstructionRunCounts();
|
||||||
|
void LogCompiledInstructions();
|
||||||
|
void CompileInstruction(UGeckoInstruction _inst);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user