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:
hrydgard
2008-12-18 10:44:03 +00:00
parent feb8dc7e6b
commit 50d72c1e59
9 changed files with 170 additions and 329 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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));

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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