Skip to content

Commit

Permalink
Merge pull request #15879 from unknownbrackets/ir-slowmem
Browse files Browse the repository at this point in the history
irjit: Validate alignment in slow memory mode
  • Loading branch information
hrydgard committed Aug 21, 2022
2 parents 58adf3e + 90517ac commit b296bc7
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 0 deletions.
1 change: 1 addition & 0 deletions Core/Core.cpp
Expand Up @@ -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";
}
Expand Down
1 change: 1 addition & 0 deletions Core/Core.h
Expand Up @@ -93,6 +93,7 @@ enum class MemoryExceptionType {
WRITE_WORD,
READ_BLOCK,
WRITE_BLOCK,
ALIGNMENT,
};
enum class ExecExceptionType {
JUMP,
Expand Down
4 changes: 4 additions & 0 deletions Core/MIPS/IR/IRCompVFPU.cpp
Expand Up @@ -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));
Expand All @@ -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));
Expand Down
1 change: 1 addition & 0 deletions Core/MIPS/IR/IRFrontend.cpp
Expand Up @@ -260,6 +260,7 @@ 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,
Expand Down
5 changes: 5 additions & 0 deletions Core/MIPS/IR/IRInst.cpp
Expand Up @@ -163,6 +163,11 @@ static const IRMeta irMeta[] = {
{ IROp::Breakpoint, "Breakpoint", "", IRFLAG_EXIT },
{ IROp::MemoryCheck, "MemoryCheck", "_GC", IRFLAG_EXIT },

{ IROp::ValidateAddress8, "ValidAddr8", "_GC", IRFLAG_EXIT },
{ IROp::ValidateAddress16, "ValidAddr16", "_GC", IRFLAG_EXIT },
{ IROp::ValidateAddress32, "ValidAddr32", "_GC", IRFLAG_EXIT },
{ IROp::ValidateAddress128, "ValidAddr128", "_GC", IRFLAG_EXIT },

{ IROp::RestoreRoundingMode, "RestoreRoundingMode", "" },
{ IROp::ApplyRoundingMode, "ApplyRoundingMode", "" },
{ IROp::UpdateRoundingMode, "UpdateRoundingMode", "" },
Expand Down
7 changes: 7 additions & 0 deletions Core/MIPS/IR/IRInst.h
Expand Up @@ -213,8 +213,15 @@ enum class IROp : u8 {
SetPCConst, // hack to make replacement know PC
CallReplacement,
Break,

// Debugging breakpoints.
Breakpoint,
MemoryCheck,

ValidateAddress8,
ValidateAddress16,
ValidateAddress32,
ValidateAddress128,
};

enum IRComparison {
Expand Down
44 changes: 44 additions & 0 deletions Core/MIPS/IR/IRInterpreter.cpp
Expand Up @@ -79,6 +79,25 @@ u32 RunMemCheck(u32 pc, u32 addr) {
return coreState != CORE_RUNNING ? 1 : 0;
}

template <uint32_t alignment>
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) {
return toss(MemoryExceptionType::ALIGNMENT);
}
return 0;
}

// We cannot use NEON on ARM32 here until we make it a hard dependency. We can, however, on ARM64.
u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) {
const IRInst *end = inst + count;
Expand Down Expand Up @@ -142,6 +161,31 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) {
mips->r[inst->dest] = ReverseBits32(mips->r[inst->src1]);
break;

case IROp::ValidateAddress8:
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, inst->src2)) {
CoreTiming::ForceCheck();
return mips->pc;
}
break;
case IROp::ValidateAddress32:
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, inst->src2)) {
CoreTiming::ForceCheck();
return mips->pc;
}
break;

case IROp::Load8:
mips->r[inst->dest] = Memory::ReadUnchecked_U8(mips->r[inst->src1] + inst->constant);
break;
Expand Down
68 changes: 68 additions & 0 deletions Core/MIPS/IR/IRPassSimplify.cpp
Expand Up @@ -5,6 +5,7 @@
#include "Common/BitSet.h"
#include "Common/Data/Convert/SmallDataConvert.h"
#include "Common/Log.h"
#include "Core/Config.h"
#include "Core/MIPS/IR/IRInterpreter.h"
#include "Core/MIPS/IR/IRPassSimplify.h"
#include "Core/MIPS/IR/IRRegCache.h"
Expand Down Expand Up @@ -622,6 +623,18 @@ bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts
}
break;

case IROp::ValidateAddress8:
case IROp::ValidateAddress16:
case IROp::ValidateAddress32:
case IROp::ValidateAddress128:
if (gpr.IsImm(inst.src1)) {
out.Write(inst.op, inst.dest, 0, out.AddConstant(gpr.GetImm(inst.src1) + inst.constant));
} else {
gpr.MapIn(inst.src1);
goto doDefault;
}
break;

case IROp::Downcount:
case IROp::SetPCConst:
goto doDefault;
Expand Down Expand Up @@ -1428,3 +1441,58 @@ bool MergeLoadStore(const IRWriter &in, IRWriter &out, const IROptions &opts) {
}
return logBlocks;
}

bool ApplyMemoryValidation(const IRWriter &in, IRWriter &out, const IROptions &opts) {
CONDITIONAL_DISABLE;
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()) {
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;
}
1 change: 1 addition & 0 deletions Core/MIPS/IR/IRPassSimplify.h
Expand Up @@ -14,3 +14,4 @@ bool ThreeOpToTwoOp(const IRWriter &in, IRWriter &out, const IROptions &opts);
bool OptimizeFPMoves(const IRWriter &in, IRWriter &out, const IROptions &opts);
bool ReorderLoadStore(const IRWriter &in, IRWriter &out, const IROptions &opts);
bool MergeLoadStore(const IRWriter &in, IRWriter &out, const IROptions &opts);
bool ApplyMemoryValidation(const IRWriter &in, IRWriter &out, const IROptions &opts);

0 comments on commit b296bc7

Please sign in to comment.