irjit: Validate alignment in slow memory mode.

This commit is contained in:
Unknown W. Brackets 2022-08-21 13:24:10 -07:00
parent 6715f41410
commit 90517ace59
6 changed files with 65 additions and 11 deletions

View File

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

View File

@ -93,6 +93,7 @@ enum class MemoryExceptionType {
WRITE_WORD,
READ_BLOCK,
WRITE_BLOCK,
ALIGNMENT,
};
enum class ExecExceptionType {
JUMP,

View File

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

View File

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

View File

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

View File

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