mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-11 00:29:11 +01: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:
parent
feb8dc7e6b
commit
50d72c1e59
@ -45,7 +45,6 @@ namespace HW
|
||||
void Init()
|
||||
{
|
||||
CoreTiming::Init();
|
||||
PPCAnalyst::Init();
|
||||
|
||||
Thunk_Init(); // not really hw, but this way we know it's inited early :P
|
||||
State_Init();
|
||||
@ -91,7 +90,6 @@ namespace HW
|
||||
State_Shutdown();
|
||||
Thunk_Shutdown();
|
||||
CoreTiming::Shutdown();
|
||||
PPCAnalyst::Shutdown();
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
|
@ -172,6 +172,7 @@ namespace Jit64
|
||||
{
|
||||
JitState js;
|
||||
JitOptions jo;
|
||||
PPCAnalyst::CodeBuffer code_buffer(32000);
|
||||
|
||||
void Init()
|
||||
{
|
||||
@ -319,7 +320,10 @@ namespace Jit64
|
||||
|
||||
//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.
|
||||
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
|
||||
b.checkedEntry = start;
|
||||
b.runCount = 0;
|
||||
|
@ -21,6 +21,7 @@
|
||||
// dependency is a little inconvenient and this is possibly a slight
|
||||
// performance hit, it's not enabled by default, but it's useful for
|
||||
// locating performance issues.
|
||||
|
||||
//#define OPROFILE_REPORT
|
||||
|
||||
#include <map>
|
||||
@ -71,10 +72,10 @@ namespace Jit64
|
||||
TRAMPOLINE_SIZE = 1024*1024,
|
||||
//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;
|
||||
|
||||
static u8 **blockCodePointers; // cut these in half and force below 2GB?
|
||||
static u8 **blockCodePointers;
|
||||
|
||||
static std::multimap<u32, int> links_to;
|
||||
|
||||
@ -133,8 +134,8 @@ namespace Jit64
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
|
||||
is full and when saving and loading states */
|
||||
// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
|
||||
// is full and when saving and loading states.
|
||||
void ClearCache()
|
||||
{
|
||||
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;
|
||||
void LinkBlock(int i)
|
||||
{
|
||||
@ -408,7 +402,6 @@ namespace Jit64
|
||||
SetCodePtr(prev_code); // reset code pointer
|
||||
}
|
||||
|
||||
#define BLR_OP 0x4e800020
|
||||
|
||||
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)
|
||||
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))
|
||||
{
|
||||
DestroyBlock(i, true);
|
||||
|
@ -278,6 +278,10 @@ void stfs(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.
|
||||
INSTRUCTION_START;
|
||||
#ifdef _M_X64
|
||||
|
@ -182,7 +182,7 @@ void psq_st(UGeckoInstruction inst)
|
||||
{
|
||||
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) {
|
||||
// Writing to FIFO. Let's do fast method.
|
||||
CVTPD2PS(XMM0, fpr.R(s));
|
||||
|
@ -40,30 +40,24 @@ namespace PPCAnalyst {
|
||||
|
||||
using namespace std;
|
||||
|
||||
PPCAnalyst::CodeOp *codebuffer;
|
||||
|
||||
enum
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void AnalyzeFunction2(Symbol &func);
|
||||
u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc);
|
||||
|
||||
// void FixUpInternalBranches(CodeOp *code, int begin, int end);
|
||||
|
||||
|
||||
#define INVALID_TARGET ((u32)-1)
|
||||
|
||||
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
|
||||
// so we have more information to work with
|
||||
void AnalyzeFunction2(Symbol &func)
|
||||
void AnalyzeFunction2(Symbol *func)
|
||||
{
|
||||
// u32 addr = func.address;
|
||||
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;
|
||||
}*/
|
||||
u32 flags = func->flags;
|
||||
|
||||
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);
|
||||
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))
|
||||
flags |= FFLAG_ONLYCALLSNICELEAFS;
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
func->flags = flags;
|
||||
}
|
||||
|
||||
// IMPORTANT - CURRENTLY ASSUMES THAT A IS A COMPARE
|
||||
@ -346,138 +283,92 @@ bool CanSwapAdjacentOps(const CodeOp &a, const CodeOp &b)
|
||||
}
|
||||
|
||||
// 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;
|
||||
u32 blockstart = address;
|
||||
memset(&st, 0, sizeof(st));
|
||||
UGeckoInstruction previnst = Memory::Read_Instruction(address-4);
|
||||
memset(st, 0, sizeof(st));
|
||||
UGeckoInstruction previnst = Memory::Read_Instruction(address - 4);
|
||||
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;
|
||||
//for now, all will return JustCopy :P
|
||||
/*
|
||||
if (f)
|
||||
int num_inst = 0;
|
||||
int numFollows = 0;
|
||||
|
||||
CodeOp *code = buffer->codebuffer;
|
||||
bool foundExit = false;
|
||||
|
||||
// Flatten! (Currently just copies, following branches is disabled)
|
||||
for (int i = 0; i < maxsize; i++, num_inst++)
|
||||
{
|
||||
if (f->flags & FFLAG_LEAF)
|
||||
memset(&code[i], 0, sizeof(CodeOp));
|
||||
code[i].address = 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);
|
||||
code[i].inst = inst;
|
||||
code[i].branchTo = -1;
|
||||
code[i].branchToIndex = -1;
|
||||
GekkoOPInfo *opinfo = GetOpInfo(inst);
|
||||
if (opinfo)
|
||||
numCycles += opinfo->numCyclesMinusOne + 1;
|
||||
_assert_msg_(GEKKO, opinfo != 0, "Invalid Op - Error flattening %08x op %08x", address + i*4, inst);
|
||||
bool follow = false;
|
||||
u32 destination;
|
||||
if (inst.OPCD == 18)
|
||||
{
|
||||
//no reason to flatten
|
||||
todo = JustCopy;
|
||||
//Is bx - should we inline? yes!
|
||||
if (inst.AA)
|
||||
destination = SignExt26(inst.LI << 2);
|
||||
else
|
||||
destination = address + SignExt26(inst.LI << 2);
|
||||
if (destination != blockstart)
|
||||
follow = true;
|
||||
}
|
||||
else if (f->flags & FFLAG_ONLYCALLSNICELEAFS)
|
||||
if (follow)
|
||||
numFollows++;
|
||||
if (numFollows > 1)
|
||||
follow = false;
|
||||
follow = false;
|
||||
if (!follow)
|
||||
{
|
||||
//inline calls if possible
|
||||
//todo = Flatten;
|
||||
todo = JustCopy;
|
||||
if (opinfo->flags & FL_ENDBLOCK) //right now we stop early
|
||||
{
|
||||
foundExit = true;
|
||||
break;
|
||||
}
|
||||
address += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
todo = JustCopy;
|
||||
address = destination;
|
||||
}
|
||||
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;
|
||||
for (int i = 0; i < maxsize; i++, realsize++)
|
||||
{
|
||||
memset(&code[i], 0, sizeof(CodeOp));
|
||||
code[i].address = 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);
|
||||
code[i].inst = inst;
|
||||
code[i].branchTo = -1;
|
||||
code[i].branchToIndex = -1;
|
||||
GekkoOPInfo *opinfo = GetOpInfo(inst);
|
||||
if (opinfo)
|
||||
numCycles += opinfo->numCyclesMinusOne + 1;
|
||||
_assert_msg_(GEKKO, opinfo != 0, "Invalid Op - Error flattening %08x op %08x",address+i*4,inst);
|
||||
int flags = opinfo->flags;
|
||||
|
||||
bool follow = false;
|
||||
u32 destination;
|
||||
if (inst.OPCD == 18)
|
||||
{
|
||||
//Is bx - should we inline? yes!
|
||||
if (inst.AA)
|
||||
destination = SignExt26(inst.LI << 2);
|
||||
else
|
||||
destination = address + SignExt26(inst.LI << 2);
|
||||
if (destination != blockstart)
|
||||
follow = true;
|
||||
}
|
||||
if (follow)
|
||||
numFollows++;
|
||||
if (numFollows > 1)
|
||||
follow = false;
|
||||
|
||||
follow = false;
|
||||
if (!follow)
|
||||
{
|
||||
if (flags & FL_ENDBLOCK) //right now we stop early
|
||||
{
|
||||
foundExit = true;
|
||||
break;
|
||||
}
|
||||
address += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
address = destination;
|
||||
}
|
||||
}
|
||||
_assert_msg_(GEKKO,foundExit,"Analyzer ERROR - Function %08x too big", blockstart);
|
||||
realsize++;
|
||||
st.numCycles = numCycles;
|
||||
FixUpInternalBranches(code,0,realsize);
|
||||
}
|
||||
else if (todo == Flatten)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
_assert_msg_(GEKKO, foundExit, "Analyzer ERROR - Function %08x too big", blockstart);
|
||||
num_inst++; // why?
|
||||
st->numCycles = numCycles;
|
||||
|
||||
// Do analysis of the code, look for dependencies etc
|
||||
int numSystemInstructions = 0;
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
gpa.firstRead[i] = -1;
|
||||
gpa.firstWrite[i] = -1;
|
||||
gpa.numReads[i] = 0;
|
||||
gpa.numWrites[i] = 0;
|
||||
gpa->firstRead[i] = -1;
|
||||
gpa->firstWrite[i] = -1;
|
||||
gpa->numReads[i] = 0;
|
||||
gpa->numWrites[i] = 0;
|
||||
}
|
||||
|
||||
gpa.any = true;
|
||||
for (size_t i = 0; i < realsize; i++)
|
||||
gpa->any = true;
|
||||
for (size_t i = 0; i < num_inst; i++)
|
||||
{
|
||||
UGeckoInstruction inst = code[i].inst;
|
||||
if (PPCTables::UsesFPU(inst))
|
||||
fpa.any = true;
|
||||
fpa->any = true;
|
||||
|
||||
code[i].wantsCR0 = false;
|
||||
code[i].wantsCR1 = false;
|
||||
@ -488,7 +379,7 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
||||
int flags = opinfo->flags;
|
||||
|
||||
if (flags & FL_TIMER)
|
||||
gpa.anyTimer = true;
|
||||
gpa->anyTimer = true;
|
||||
|
||||
// Does the instruction output CR0?
|
||||
if (flags & FL_RC_BIT)
|
||||
@ -521,37 +412,37 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
||||
if (flags & FL_OUT_A)
|
||||
{
|
||||
code[i].regsOut[numOut++] = inst.RA;
|
||||
gpa.numWrites[inst.RA]++;
|
||||
gpa->numWrites[inst.RA]++;
|
||||
}
|
||||
if (flags & FL_OUT_D)
|
||||
{
|
||||
code[i].regsOut[numOut++] = inst.RD;
|
||||
gpa.numWrites[inst.RD]++;
|
||||
gpa->numWrites[inst.RD]++;
|
||||
}
|
||||
if (flags & FL_OUT_S)
|
||||
{
|
||||
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))
|
||||
{
|
||||
code[i].regsIn[numIn++] = inst.RA;
|
||||
gpa.numReads[inst.RA]++;
|
||||
gpa->numReads[inst.RA]++;
|
||||
}
|
||||
if (flags & FL_IN_B)
|
||||
{
|
||||
code[i].regsIn[numIn++] = inst.RB;
|
||||
gpa.numReads[inst.RB]++;
|
||||
gpa->numReads[inst.RB]++;
|
||||
}
|
||||
if (flags & FL_IN_C)
|
||||
{
|
||||
code[i].regsIn[numIn++] = inst.RC;
|
||||
gpa.numReads[inst.RC]++;
|
||||
gpa->numReads[inst.RC]++;
|
||||
}
|
||||
if (flags & FL_IN_S)
|
||||
{
|
||||
code[i].regsIn[numIn++] = inst.RS;
|
||||
gpa.numReads[inst.RS]++;
|
||||
gpa->numReads[inst.RS]++;
|
||||
}
|
||||
|
||||
switch (opinfo->type)
|
||||
@ -583,10 +474,10 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
||||
int r = code[i].regsIn[j];
|
||||
if (r < 0 || r > 31)
|
||||
PanicAlert("wtf");
|
||||
if (gpa.firstRead[r] == -1)
|
||||
gpa.firstRead[r] = (short)(i);
|
||||
gpa.lastRead[r] = (short)(i);
|
||||
gpa.numReads[r]++;
|
||||
if (gpa->firstRead[r] == -1)
|
||||
gpa->firstRead[r] = (short)(i);
|
||||
gpa->lastRead[r] = (short)(i);
|
||||
gpa->numReads[r]++;
|
||||
}
|
||||
|
||||
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];
|
||||
if (r < 0 || r > 31)
|
||||
PanicAlert("wtf");
|
||||
if (gpa.firstWrite[r] == -1)
|
||||
gpa.firstWrite[r] = (short)(i);
|
||||
gpa.lastWrite[r] = (short)(i);
|
||||
gpa.numWrites[r]++;
|
||||
if (gpa->firstWrite[r] == -1)
|
||||
gpa->firstWrite[r] = (short)(i);
|
||||
gpa->lastWrite[r] = (short)(i);
|
||||
gpa->numWrites[r]++;
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
for (int i = 0; i < (realsize - 2); i++)
|
||||
for (int i = 0; i < num_inst - 2; i++)
|
||||
{
|
||||
CodeOp &a = code[i];
|
||||
CodeOp &b = code[i + 1];
|
||||
@ -628,7 +519,7 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
||||
bool wantsCR0 = true;
|
||||
bool wantsCR1 = true;
|
||||
bool wantsPS1 = true;
|
||||
for (int i = realsize - 1; i; i--)
|
||||
for (int i = num_inst - 1; i; i--)
|
||||
{
|
||||
if (code[i].outputCR0)
|
||||
wantsCR0 = false;
|
||||
@ -644,40 +535,11 @@ CodeOp *Flatten(u32 address, int &realsize, BlockStats &st, BlockRegStats &gpa,
|
||||
code[i].wantsPS1 = wantsPS1;
|
||||
}
|
||||
|
||||
// Time for code shuffling, taking into account the above dependency analysis.
|
||||
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;
|
||||
*realsize = num_inst;
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
// Most functions that are relevant to analyze should be
|
||||
// called by another function. Therefore, let's scan the
|
||||
// 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");
|
||||
continue;
|
||||
}
|
||||
AnalyzeFunction2(iter->second);
|
||||
AnalyzeFunction2(&(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)
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
|
@ -76,13 +76,20 @@ struct BlockRegStats
|
||||
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 FindFunctions(u32 startAddr, u32 endAddr, SymbolDB *func_db);
|
||||
bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size = 0);
|
||||
|
||||
|
@ -122,8 +122,7 @@ Interpreter::_interpreterInstruction GetInterpreterOp(UGeckoInstruction _inst)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GekkoOPTemplate primarytable[] =
|
||||
static GekkoOPTemplate primarytable[] =
|
||||
{
|
||||
{4, Interpreter::RunTable4, DynaRunTable4, {"RunTable4", OPTYPE_SUBTABLE | (4<<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}},
|
||||
};
|
||||
|
||||
GekkoOPTemplate table4[] =
|
||||
static GekkoOPTemplate table4[] =
|
||||
{ //SUBOP10
|
||||
{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}},
|
||||
@ -222,7 +221,7 @@ GekkoOPTemplate table4[] =
|
||||
{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}},
|
||||
{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}},
|
||||
{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}},
|
||||
};
|
||||
|
||||
GekkoOPTemplate table19[] =
|
||||
static GekkoOPTemplate table19[] =
|
||||
{
|
||||
{528, Interpreter::bcctrx, Jit64::bcctrx, {"bcctrx", 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}},
|
||||
{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}},
|
||||
};
|
||||
|
||||
GekkoOPTemplate table31_2[] =
|
||||
static GekkoOPTemplate table31_2[] =
|
||||
{
|
||||
{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}},
|
||||
@ -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}},
|
||||
};
|
||||
|
||||
GekkoOPTemplate table59[] =
|
||||
static GekkoOPTemplate table59[] =
|
||||
{
|
||||
{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}},
|
||||
@ -420,7 +419,7 @@ GekkoOPTemplate table59[] =
|
||||
{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}},
|
||||
{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}},
|
||||
};
|
||||
|
||||
GekkoOPTemplate table63_2[] =
|
||||
static GekkoOPTemplate table63_2[] =
|
||||
{
|
||||
{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}},
|
||||
@ -455,7 +454,10 @@ GekkoOPTemplate table63_2[] =
|
||||
{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)
|
||||
{
|
||||
@ -500,7 +502,7 @@ bool PPCTables::UsesFPU(UGeckoInstruction _inst)
|
||||
}
|
||||
}
|
||||
|
||||
void PPCTables::InitTables()
|
||||
void InitTables()
|
||||
{
|
||||
//clear
|
||||
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);
|
||||
return info != 0;
|
||||
}
|
||||
|
||||
void PPCTables::CountInstruction(UGeckoInstruction _inst)
|
||||
void CountInstruction(UGeckoInstruction _inst)
|
||||
{
|
||||
GekkoOPInfo *info = GetOpInfo(_inst);
|
||||
if (info)
|
||||
info->runCount++;
|
||||
}
|
||||
|
||||
struct inf
|
||||
void PrintInstructionRunCounts()
|
||||
{
|
||||
const char *name;
|
||||
int count;
|
||||
bool operator < (const inf &o) const
|
||||
struct inf
|
||||
{
|
||||
return count > o.count;
|
||||
}
|
||||
};
|
||||
|
||||
void PPCTables::PrintInstructionRunCounts()
|
||||
{
|
||||
const char *name;
|
||||
int count;
|
||||
bool operator < (const inf &o) const
|
||||
{
|
||||
return count > o.count;
|
||||
}
|
||||
};
|
||||
std::vector<inf> temp;
|
||||
for (int i = 0; i < m_numInstructions; i++)
|
||||
{
|
||||
@ -712,7 +713,7 @@ void PPCTables::PrintInstructionRunCounts()
|
||||
}
|
||||
|
||||
//TODO move to LogManager
|
||||
void PPCTables::LogCompiledInstructions()
|
||||
void LogCompiledInstructions()
|
||||
{
|
||||
static int time = 0;
|
||||
FILE *f = fopen(StringFromFormat(FULL_LOGS_DIR "inst_log%i.txt", time).c_str(), "w");
|
||||
@ -740,3 +741,5 @@ void PPCTables::LogCompiledInstructions()
|
||||
#endif
|
||||
time++;
|
||||
}
|
||||
|
||||
} // namespace
|
@ -71,6 +71,18 @@ enum
|
||||
OPTYPE_UNKNOWN ,
|
||||
};
|
||||
|
||||
enum {
|
||||
OPCD_HLEFUNCTION = 1,
|
||||
OPCD_COMPILEDBLOCK = 2,
|
||||
OPCD_BCx = 16,
|
||||
OPCD_SC = 17,
|
||||
OPCD_Bx = 18,
|
||||
};
|
||||
|
||||
enum {
|
||||
OP_BLR = 0x4e800020,
|
||||
};
|
||||
|
||||
struct GekkoOPInfo
|
||||
{
|
||||
const char *opname;
|
||||
@ -85,21 +97,21 @@ struct GekkoOPInfo
|
||||
GekkoOPInfo *GetOpInfo(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();
|
||||
static bool IsValidInstruction(UGeckoInstruction _instCode);
|
||||
static bool UsesFPU(UGeckoInstruction _inst);
|
||||
typedef void (*_recompilerInstruction) (UGeckoInstruction instCode);
|
||||
typedef void (*_interpreterInstruction)(UGeckoInstruction instCode);
|
||||
|
||||
static void CountInstruction(UGeckoInstruction _inst);
|
||||
static void PrintInstructionRunCounts();
|
||||
static void LogCompiledInstructions();
|
||||
void InitTables();
|
||||
bool IsValidInstruction(UGeckoInstruction _instCode);
|
||||
bool UsesFPU(UGeckoInstruction _inst);
|
||||
|
||||
static void CompileInstruction(UGeckoInstruction _inst);
|
||||
};
|
||||
void CountInstruction(UGeckoInstruction _inst);
|
||||
void PrintInstructionRunCounts();
|
||||
void LogCompiledInstructions();
|
||||
void CompileInstruction(UGeckoInstruction _inst);
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user