CPU/CodeCache: Don't choke on indirect branches in delay slot

Fixes emulator crash/memory usage explosion in Shadow Master.
This commit is contained in:
Connor McLaughlin 2020-12-14 01:21:49 +10:00
parent d7c3a0137f
commit 5164840c25
3 changed files with 25 additions and 0 deletions

View File

@ -527,6 +527,11 @@ bool CompileBlock(CodeBlock* block)
Log_WarningPrintf("Conditional branch delay slot at %08X, skipping block", cbi.pc);
return false;
}
if (!IsDirectBranchInstruction(cbi.instruction))
{
Log_WarningPrintf("Indirect branch in delay slot at %08X, skipping block", cbi.pc);
return false;
}
// change the pc for the second branch's delay slot, it comes from the first branch
const CodeBlockInstruction& prev_cbi = block->instructions.back();

View File

@ -80,6 +80,24 @@ bool IsUnconditionalBranchInstruction(const Instruction& instruction)
}
}
bool IsDirectBranchInstruction(const Instruction& instruction)
{
switch (instruction.op)
{
case InstructionOp::j:
case InstructionOp::jal:
case InstructionOp::b:
case InstructionOp::beq:
case InstructionOp::bgtz:
case InstructionOp::blez:
case InstructionOp::bne:
return true;
default:
return false;
}
}
u32 GetBranchInstructionTarget(const Instruction& instruction, u32 instruction_pc)
{
switch (instruction.op)
@ -96,6 +114,7 @@ u32 GetBranchInstructionTarget(const Instruction& instruction, u32 instruction_p
return instruction_pc + 4 + (instruction.i.imm_sext32() << 2);
default:
Panic("Trying to get branch target of indirect or invalid branch");
return instruction_pc;
}
}

View File

@ -213,6 +213,7 @@ union Instruction
// Instruction helpers.
bool IsBranchInstruction(const Instruction& instruction);
bool IsUnconditionalBranchInstruction(const Instruction& instruction);
bool IsDirectBranchInstruction(const Instruction& instruction);
u32 GetBranchInstructionTarget(const Instruction& instruction, u32 instruction_pc);
bool IsMemoryLoadInstruction(const Instruction& instruction);
bool IsMemoryStoreInstruction(const Instruction& instruction);