mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Fix some replace-related bugs. Add "jal" replace inlining, not activated.
This commit is contained in:
parent
b2d0f37d96
commit
1e300447e1
8 changed files with 90 additions and 26 deletions
|
@ -52,6 +52,7 @@ static int Replace_atan2f() {
|
|||
RETURNF(atan2f(f1, f2));
|
||||
return 120; // guess number of cycles
|
||||
}
|
||||
|
||||
// Should probably do JIT versions of this, possibly ones that only delegate
|
||||
// large copies to a C function.
|
||||
static int Replace_memcpy() {
|
||||
|
@ -151,12 +152,11 @@ static const ReplacementTableEntry entries[] = {
|
|||
{ "memcpy", &Replace_memcpy, 0, 0},
|
||||
{ "memmove", &Replace_memmove, 0, 0},
|
||||
{ "memset", &Replace_memset, 0, 0},
|
||||
|
||||
{ "strlen", &Replace_strlen, 0, 0},
|
||||
{ "strcpy", &Replace_strcpy, 0, 0},
|
||||
{ "fabsf", 0, &MIPSComp::Jit::Replace_fabsf, REPFLAG_ALLOWINLINE},
|
||||
{ "strcmp", &Replace_strcmp, 0, 0},
|
||||
{ "strncmp", &Replace_strncmp, 0, 0},
|
||||
{ "fabsf", 0, &MIPSComp::Jit::Replace_fabsf, REPFLAG_ALLOWINLINE},
|
||||
// { "vmmul_q_transp", &Replace_vmmul_q_transp, 0, 0},
|
||||
{}
|
||||
};
|
||||
|
@ -208,11 +208,16 @@ void WriteReplaceInstruction(u32 address, u64 hash, int size) {
|
|||
}
|
||||
|
||||
bool GetReplacedOpAt(u32 address, u32 *op) {
|
||||
auto iter = replacedInstructions.find(address);
|
||||
if (iter != replacedInstructions.end()) {
|
||||
*op = iter->second;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
u32 instr = Memory::Read_U32(address);
|
||||
if (MIPS_IS_REPLACEMENT(instr)) {
|
||||
auto iter = replacedInstructions.find(address);
|
||||
if (iter != replacedInstructions.end()) {
|
||||
*op = iter->second;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*op = instr;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -334,6 +334,7 @@ namespace MIPSDis
|
|||
const char *name = MIPSGetName(op);
|
||||
sprintf(out, "%s\t->$%08x",name,addr);
|
||||
}
|
||||
|
||||
void Dis_JumpRegType(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rs = _RS;
|
||||
|
@ -363,11 +364,18 @@ namespace MIPSDis
|
|||
|
||||
void Dis_Emuhack(MIPSOpcode op, char *out)
|
||||
{
|
||||
//const char *name = MIPSGetName(op);
|
||||
//sprintf(out,"%s\t-",name);
|
||||
out[0]='*';
|
||||
out[1]=0;
|
||||
// MIPSDisAsm(MIPSComp::GetOriginalOp(op), currentDebugMIPS->GetPC(), out+1);
|
||||
switch (op.encoding >> 24) {
|
||||
case 0x68:
|
||||
strcpy(out, "* jitblock");
|
||||
break;
|
||||
case 0x6a:
|
||||
strcpy(out, "* replacement");
|
||||
break;
|
||||
default:
|
||||
out[0]='*';
|
||||
out[1]=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -552,6 +552,10 @@ void Jit::Comp_Jump(MIPSOpcode op)
|
|||
break;
|
||||
|
||||
case 3: //jal
|
||||
// Special case for branches to "replace functions":
|
||||
// if (ReplaceJalTo(targetAddr))
|
||||
// return;
|
||||
|
||||
// Save return address - might be overwritten by delay slot.
|
||||
gpr.SetImm(MIPS_REG_RA, js.compilerPC + 8);
|
||||
CompileDelaySlot(DELAYSLOT_NICE);
|
||||
|
|
|
@ -27,6 +27,7 @@ int Jit::Replace_fabsf() {
|
|||
fpr.MapReg(0, MAP_DIRTY | MAP_NOINIT);
|
||||
MOVSS(fpr.RX(0), fpr.R(12));
|
||||
ANDPS(fpr.RX(0), M((void *)&ssNoSignMask));
|
||||
fpr.ReleaseSpillLocks();
|
||||
return 4; // Number of instructions in the MIPS function
|
||||
}
|
||||
|
||||
|
|
|
@ -229,7 +229,7 @@ void Jit::CompileDelaySlot(int flags, RegCacheState *state)
|
|||
SAVE_FLAGS; // preserve flag around the delay slot!
|
||||
|
||||
js.inDelaySlot = true;
|
||||
MIPSOpcode op = Memory::Read_Instruction(addr);
|
||||
MIPSOpcode op = Memory::Read_Opcode_JIT(addr);
|
||||
MIPSCompileOp(op);
|
||||
js.inDelaySlot = false;
|
||||
|
||||
|
@ -323,7 +323,7 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b)
|
|||
// Jit breakpoints are quite fast, so let's do them in release too.
|
||||
CheckJitBreakpoint(js.compilerPC, 0);
|
||||
|
||||
MIPSOpcode inst = Memory::Read_Instruction(js.compilerPC);
|
||||
MIPSOpcode inst = Memory::Read_Opcode_JIT(js.compilerPC);
|
||||
js.downcountAmount += MIPSGetInstructionCycleEstimate(inst);
|
||||
|
||||
MIPSCompileOp(inst);
|
||||
|
@ -372,6 +372,35 @@ void Jit::Comp_RunBlock(MIPSOpcode op)
|
|||
ERROR_LOG(JIT, "Comp_RunBlock");
|
||||
}
|
||||
|
||||
bool Jit::ReplaceJalTo(u32 dest) {
|
||||
MIPSOpcode op(Memory::Read_U32(dest));
|
||||
if (!MIPS_IS_REPLACEMENT(dest))
|
||||
return false;
|
||||
|
||||
int index = op.encoding & MIPS_EMUHACK_VALUE_MASK;
|
||||
const ReplacementTableEntry *entry = GetReplacementFunc(index);
|
||||
if (!entry) {
|
||||
ERROR_LOG(HLE, "ReplaceJalTo: Invalid replacement op %08x at %08x", op.encoding, dest);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Warning - this might be bad if the code at the destination changes...
|
||||
if (entry->flags & REPFLAG_ALLOWINLINE) {
|
||||
// Jackpot! Just do it, no flushing. The code will be entirely inlined.
|
||||
|
||||
// First, compile the delay slot. It's unconditional so no issues.
|
||||
CompileDelaySlot(DELAYSLOT_NICE);
|
||||
// Technically, we should write the unused return address to RA, but meh.
|
||||
MIPSReplaceFunc repl = entry->jitReplaceFunc;
|
||||
int cycles = (this->*repl)();
|
||||
js.downcountAmount += cycles;
|
||||
// No writing exits, keep going!
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_ReplacementFunc(MIPSOpcode op)
|
||||
{
|
||||
// We get here if we execute the first instruction of a replaced function. This means
|
||||
|
|
|
@ -167,12 +167,14 @@ public:
|
|||
|
||||
void ClearCache();
|
||||
void ClearCacheAt(u32 em_address, int length = 4);
|
||||
|
||||
private:
|
||||
void GetStateAndFlushAll(RegCacheState &state);
|
||||
void RestoreState(const RegCacheState state);
|
||||
void FlushAll();
|
||||
void FlushPrefixV();
|
||||
void WriteDowncount(int offset = 0);
|
||||
bool ReplaceJalTo(u32 dest);
|
||||
|
||||
// See CompileDelaySlotFlags for flags.
|
||||
void CompileDelaySlot(int flags, RegCacheState *state = NULL);
|
||||
|
|
|
@ -171,15 +171,22 @@ void Clear()
|
|||
memset(m_pVRAM, 0, VRAM_SIZE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Opcode Read_Instruction(u32 address)
|
||||
{
|
||||
Opcode inst = Opcode(Read_U32(address));
|
||||
if (MIPS_IS_RUNBLOCK(inst.encoding) && MIPSComp::jit)
|
||||
{
|
||||
if (MIPS_IS_RUNBLOCK(inst.encoding) && MIPSComp::jit) {
|
||||
JitBlockCache *bc = MIPSComp::jit->GetBlockCache();
|
||||
int block_num = bc->GetBlockNumberFromEmuHackOp(inst, true);
|
||||
if (block_num >= 0) {
|
||||
return bc->GetOriginalFirstOp(block_num);
|
||||
inst = bc->GetOriginalFirstOp(block_num);
|
||||
/*
|
||||
u32 op;
|
||||
if (GetReplacedOpAt(address, &op)) {
|
||||
return Opcode(op);
|
||||
}*/
|
||||
return inst;
|
||||
} else {
|
||||
return inst;
|
||||
}
|
||||
|
@ -197,7 +204,18 @@ Opcode Read_Instruction(u32 address)
|
|||
|
||||
Opcode Read_Opcode_JIT(u32 address)
|
||||
{
|
||||
return Read_Instruction(address);
|
||||
Opcode inst = Opcode(Read_U32(address));
|
||||
if (MIPS_IS_RUNBLOCK(inst.encoding) && MIPSComp::jit) {
|
||||
JitBlockCache *bc = MIPSComp::jit->GetBlockCache();
|
||||
int block_num = bc->GetBlockNumberFromEmuHackOp(inst, true);
|
||||
if (block_num >= 0) {
|
||||
return bc->GetOriginalFirstOp(block_num);
|
||||
} else {
|
||||
return inst;
|
||||
}
|
||||
} else {
|
||||
return inst;
|
||||
}
|
||||
}
|
||||
|
||||
// WARNING! No checks!
|
||||
|
|
|
@ -133,17 +133,14 @@ struct Opcode {
|
|||
u32 encoding;
|
||||
};
|
||||
|
||||
// used by JIT to read instructions
|
||||
// used by JIT to read instructions. Does not resolve replacements.
|
||||
Opcode Read_Opcode_JIT(const u32 _Address);
|
||||
// used by JIT. uses iCacheJIT. Reads in the "Locked cache" mode
|
||||
// used by JIT. Reads in the "Locked cache" mode
|
||||
void Write_Opcode_JIT(const u32 _Address, const Opcode _Value);
|
||||
// this is used by Debugger a lot.
|
||||
// For now, just reads from memory!
|
||||
|
||||
// Should be used by analyzers, disassemblers etc. Does resolve replacements.
|
||||
Opcode Read_Instruction(const u32 _Address);
|
||||
|
||||
|
||||
// For use by emulator
|
||||
|
||||
u8 Read_U8(const u32 _Address);
|
||||
u16 Read_U16(const u32 _Address);
|
||||
u32 Read_U32(const u32 _Address);
|
||||
|
|
Loading…
Add table
Reference in a new issue