mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-05 13:06:52 +00:00
irjit: Validate alignment in slow memory mode.
This commit is contained in:
parent
6715f41410
commit
90517ace59
@ -419,6 +419,7 @@ const char *MemoryExceptionTypeAsString(MemoryExceptionType type) {
|
||||
case MemoryExceptionType::WRITE_WORD: return "Write Word";
|
||||
case MemoryExceptionType::READ_BLOCK: return "Read Block";
|
||||
case MemoryExceptionType::WRITE_BLOCK: return "Read/Write Block";
|
||||
case MemoryExceptionType::ALIGNMENT: return "Alignment";
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ enum class MemoryExceptionType {
|
||||
WRITE_WORD,
|
||||
READ_BLOCK,
|
||||
WRITE_BLOCK,
|
||||
ALIGNMENT,
|
||||
};
|
||||
enum class ExecExceptionType {
|
||||
JUMP,
|
||||
|
@ -330,6 +330,8 @@ namespace MIPSComp {
|
||||
ir.Write(IROp::LoadVec4, vregs[0], rs, ir.AddConstant(imm));
|
||||
} else {
|
||||
// Let's not even bother with "vertical" loads for now.
|
||||
if (!g_Config.bFastMemory)
|
||||
ir.Write({ IROp::ValidateAddress128, { 0 }, (u8)rs, 0, (u32)imm });
|
||||
ir.Write(IROp::LoadFloat, vregs[0], rs, ir.AddConstant(imm));
|
||||
ir.Write(IROp::LoadFloat, vregs[1], rs, ir.AddConstant(imm + 4));
|
||||
ir.Write(IROp::LoadFloat, vregs[2], rs, ir.AddConstant(imm + 8));
|
||||
@ -342,6 +344,8 @@ namespace MIPSComp {
|
||||
ir.Write(IROp::StoreVec4, vregs[0], rs, ir.AddConstant(imm));
|
||||
} else {
|
||||
// Let's not even bother with "vertical" stores for now.
|
||||
if (!g_Config.bFastMemory)
|
||||
ir.Write({ IROp::ValidateAddress128, { 0 }, (u8)rs, 1, (u32)imm });
|
||||
ir.Write(IROp::StoreFloat, vregs[0], rs, ir.AddConstant(imm));
|
||||
ir.Write(IROp::StoreFloat, vregs[1], rs, ir.AddConstant(imm + 4));
|
||||
ir.Write(IROp::StoreFloat, vregs[2], rs, ir.AddConstant(imm + 8));
|
||||
|
@ -260,11 +260,11 @@ void IRFrontend::DoJit(u32 em_address, std::vector<IRInst> &instructions, u32 &m
|
||||
IRWriter *code = &ir;
|
||||
if (!js.hadBreakpoints) {
|
||||
static const IRPassFunc passes[] = {
|
||||
&ApplyMemoryValidation,
|
||||
&RemoveLoadStoreLeftRight,
|
||||
&OptimizeFPMoves,
|
||||
&PropagateConstants,
|
||||
&PurgeTemps,
|
||||
&ApplyMemoryValidation,
|
||||
// &ReorderLoadStore,
|
||||
// &MergeLoadStore,
|
||||
// &ThreeOpToTwoOp,
|
||||
|
@ -80,14 +80,20 @@ u32 RunMemCheck(u32 pc, u32 addr) {
|
||||
}
|
||||
|
||||
template <uint32_t alignment>
|
||||
u32 RunValidateAddress(u32 pc, u32 addr) {
|
||||
if (!Memory::IsValidRange(addr, alignment)) {
|
||||
Core_MemoryException(addr, pc, MemoryExceptionType::UNKNOWN);
|
||||
u32 RunValidateAddress(u32 pc, u32 addr, u32 isWrite) {
|
||||
const auto toss = [&](MemoryExceptionType t) {
|
||||
Core_MemoryException(addr, pc, t);
|
||||
return coreState != CORE_RUNNING ? 1 : 0;
|
||||
};
|
||||
|
||||
if (!Memory::IsValidRange(addr, alignment)) {
|
||||
MemoryExceptionType t = isWrite == 1 ? MemoryExceptionType::WRITE_WORD : MemoryExceptionType::READ_WORD;
|
||||
if (alignment > 4)
|
||||
t = isWrite ? MemoryExceptionType::WRITE_BLOCK : MemoryExceptionType::READ_BLOCK;
|
||||
return toss(t);
|
||||
}
|
||||
if (alignment > 1 && (addr & (alignment - 1)) != 0) {
|
||||
Core_MemoryException(addr, pc, MemoryExceptionType::UNKNOWN);
|
||||
return coreState != CORE_RUNNING ? 1 : 0;
|
||||
return toss(MemoryExceptionType::ALIGNMENT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -156,25 +162,25 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) {
|
||||
break;
|
||||
|
||||
case IROp::ValidateAddress8:
|
||||
if (RunValidateAddress<1>(mips->pc, mips->r[inst->src1] + inst->constant)) {
|
||||
if (RunValidateAddress<1>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) {
|
||||
CoreTiming::ForceCheck();
|
||||
return mips->pc;
|
||||
}
|
||||
break;
|
||||
case IROp::ValidateAddress16:
|
||||
if (RunValidateAddress<2>(mips->pc, mips->r[inst->src1] + inst->constant)) {
|
||||
if (RunValidateAddress<2>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) {
|
||||
CoreTiming::ForceCheck();
|
||||
return mips->pc;
|
||||
}
|
||||
break;
|
||||
case IROp::ValidateAddress32:
|
||||
if (RunValidateAddress<4>(mips->pc, mips->r[inst->src1] + inst->constant)) {
|
||||
if (RunValidateAddress<4>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) {
|
||||
CoreTiming::ForceCheck();
|
||||
return mips->pc;
|
||||
}
|
||||
break;
|
||||
case IROp::ValidateAddress128:
|
||||
if (RunValidateAddress<16>(mips->pc, mips->r[inst->src1] + inst->constant)) {
|
||||
if (RunValidateAddress<16>(mips->pc, mips->r[inst->src1] + inst->constant, inst->src2)) {
|
||||
CoreTiming::ForceCheck();
|
||||
return mips->pc;
|
||||
}
|
||||
|
@ -1447,9 +1447,51 @@ bool ApplyMemoryValidation(const IRWriter &in, IRWriter &out, const IROptions &o
|
||||
if (g_Config.bFastMemory)
|
||||
DISABLE;
|
||||
|
||||
const auto addValidate = [&out](IROp validate, const IRInst &inst, bool isStore) {
|
||||
out.Write({ validate, { 0 }, inst.src1, isStore ? (u8)1 : (u8)0, inst.constant });
|
||||
};
|
||||
|
||||
// TODO: Could be smart about not double-validating an address that has a load / store, etc.
|
||||
bool logBlocks = false;
|
||||
for (IRInst inst : in.GetInstructions()) {
|
||||
// TODO
|
||||
switch (inst.op) {
|
||||
case IROp::Load8:
|
||||
case IROp::Load8Ext:
|
||||
case IROp::Store8:
|
||||
addValidate(IROp::ValidateAddress8, inst, inst.op == IROp::Store8);
|
||||
break;
|
||||
|
||||
case IROp::Load16:
|
||||
case IROp::Load16Ext:
|
||||
case IROp::Store16:
|
||||
addValidate(IROp::ValidateAddress16, inst, inst.op == IROp::Store16);
|
||||
break;
|
||||
|
||||
case IROp::Load32:
|
||||
case IROp::LoadFloat:
|
||||
case IROp::Store32:
|
||||
case IROp::StoreFloat:
|
||||
addValidate(IROp::ValidateAddress32, inst, inst.op == IROp::Store32 || inst.op == IROp::StoreFloat);
|
||||
break;
|
||||
|
||||
case IROp::LoadVec4:
|
||||
case IROp::StoreVec4:
|
||||
addValidate(IROp::ValidateAddress128, inst, inst.op == IROp::StoreVec4);
|
||||
break;
|
||||
|
||||
case IROp::Load32Left:
|
||||
case IROp::Load32Right:
|
||||
case IROp::Store32Left:
|
||||
case IROp::Store32Right:
|
||||
// This explicitly does not require alignment, so validate as an 8-bit operation.
|
||||
addValidate(IROp::ValidateAddress8, inst, inst.op == IROp::Store32Left || inst.op == IROp::Store32Right);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Always write out the original. We're only adding.
|
||||
out.Write(inst);
|
||||
}
|
||||
return logBlocks;
|
||||
|
Loading…
x
Reference in New Issue
Block a user