Skip to content
Permalink
Browse files
Merge pull request #10162 from JosJuice/jitarm64-memcheck
JitArm64: Implement memcheck
  • Loading branch information
JMC47 committed Nov 21, 2021
2 parents e5a4a86 + 5490797 commit d2ca103
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 190 deletions.
@@ -498,24 +498,41 @@ void JitArm64::WriteExceptionExit(ARM64Reg dest, bool only_external, bool always
B(dispatcher);
}

void JitArm64::WriteConditionalExceptionExit(int exception)
void JitArm64::WriteConditionalExceptionExit(int exception, u64 increment_sp_on_exit)
{
ARM64Reg WA = gpr.GetReg();
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(Exceptions));
FixupBranch noException = TBZ(WA, IntLog2(exception));
WriteConditionalExceptionExit(exception, WA, Arm64Gen::ARM64Reg::INVALID_REG,
increment_sp_on_exit);
gpr.Unlock(WA);
}

void JitArm64::WriteConditionalExceptionExit(int exception, ARM64Reg temp_gpr, ARM64Reg temp_fpr,
u64 increment_sp_on_exit)
{
LDR(IndexType::Unsigned, temp_gpr, PPC_REG, PPCSTATE_OFF(Exceptions));
FixupBranch no_exception = TBZ(temp_gpr, IntLog2(exception));

const bool switch_to_far_code = !IsInFarCode();

FixupBranch handleException = B();
SwitchToFarCode();
SetJumpTarget(handleException);
if (switch_to_far_code)
{
FixupBranch handle_exception = B();
SwitchToFarCode();
SetJumpTarget(handle_exception);
}

if (increment_sp_on_exit != 0)
ADDI2R(ARM64Reg::SP, ARM64Reg::SP, increment_sp_on_exit, temp_gpr);

gpr.Flush(FlushMode::MaintainState, WA);
fpr.Flush(FlushMode::MaintainState, ARM64Reg::INVALID_REG);
gpr.Flush(FlushMode::MaintainState, temp_gpr);
fpr.Flush(FlushMode::MaintainState, temp_fpr);

WriteExceptionExit(js.compilerPC, false, true);

SwitchToNearCode();
SetJumpTarget(noException);
gpr.Unlock(WA);
if (switch_to_far_code)
SwitchToNearCode();

SetJumpTarget(no_exception);
}

bool JitArm64::HandleFunctionHooking(u32 address)
@@ -221,7 +221,7 @@ class JitArm64 : public JitBase, public Arm64Gen::ARM64CodeBlock, public CommonA
BitSet32 fprs_to_push = BitSet32(0), bool emitting_routine = false);
// Loadstore routines
void SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 offset, bool update);
void SafeStoreFromReg(s32 dest, u32 value, s32 regOffset, u32 flags, s32 offset);
void SafeStoreFromReg(s32 dest, u32 value, s32 regOffset, u32 flags, s32 offset, bool update);
// If lookup succeeds, writes upper 15 bits of physical address to addr_out. If not,
// jumps to the returned FixupBranch. Clobbers tmp and the 17 lower bits of addr_out.
Arm64Gen::FixupBranch BATAddressLookup(Arm64Gen::ARM64Reg addr_out, Arm64Gen::ARM64Reg addr_in,
@@ -265,7 +265,10 @@ class JitArm64 : public JitBase, public Arm64Gen::ARM64CodeBlock, public CommonA
bool always_exception = false);
void WriteExceptionExit(Arm64Gen::ARM64Reg dest, bool only_external = false,
bool always_exception = false);
void WriteConditionalExceptionExit(int exception);
void WriteConditionalExceptionExit(int exception, u64 increment_sp_on_exit = 0);
void WriteConditionalExceptionExit(int exception, Arm64Gen::ARM64Reg temp_gpr,
Arm64Gen::ARM64Reg temp_fpr = Arm64Gen::ARM64Reg::INVALID_REG,
u64 increment_sp_on_exit = 0);
void FakeLKExit(u32 exit_address_after_return);
void WriteBLRExit(Arm64Gen::ARM64Reg dest);

@@ -6,6 +6,7 @@
#include <optional>
#include <string>

#include "Common/Align.h"
#include "Common/BitSet.h"
#include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h"
@@ -15,6 +16,7 @@
#include "Common/Swap.h"

#include "Core/HW/Memmap.h"
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/JitArm64/Jit.h"
#include "Core/PowerPC/JitArm64/Jit_Util.h"
#include "Core/PowerPC/JitArmCommon/BackPatch.h"
@@ -56,6 +58,8 @@ void JitArm64::EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, AR
ARM64Reg addr, BitSet32 gprs_to_push, BitSet32 fprs_to_push,
bool emitting_routine)
{
const u32 access_size = BackPatchInfo::GetFlagSize(flags);

bool in_far_code = false;
const u8* fastmem_start = GetCodePtr();
std::optional<FixupBranch> slowmem_fixup;
@@ -75,11 +79,11 @@ void JitArm64::EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, AR
ARM64Reg temp = ARM64Reg::D0;
temp = ByteswapBeforeStore(this, &m_float_emit, temp, EncodeRegToDouble(RS), flags, true);

m_float_emit.STR(BackPatchInfo::GetFlagSize(flags), temp, MEM_REG, addr);
m_float_emit.STR(access_size, temp, MEM_REG, addr);
}
else if ((flags & BackPatchInfo::FLAG_LOAD) && (flags & BackPatchInfo::FLAG_FLOAT))
{
m_float_emit.LDR(BackPatchInfo::GetFlagSize(flags), EncodeRegToDouble(RS), MEM_REG, addr);
m_float_emit.LDR(access_size, EncodeRegToDouble(RS), MEM_REG, addr);

ByteswapAfterLoad(this, &m_float_emit, EncodeRegToDouble(RS), EncodeRegToDouble(RS), flags,
true, false);
@@ -120,6 +124,8 @@ void JitArm64::EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, AR

if (!fastmem || do_farcode)
{
const bool memcheck = jo.memcheck && !emitting_routine;

if (fastmem && do_farcode)
{
in_far_code = true;
@@ -136,12 +142,28 @@ void JitArm64::EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, AR
if (slowmem_fixup)
SetJumpTarget(*slowmem_fixup);

ABI_PushRegisters(gprs_to_push);
const ARM64Reg temp_gpr = flags & BackPatchInfo::FLAG_LOAD ? ARM64Reg::W30 : ARM64Reg::W0;
const int temp_gpr_index = DecodeReg(temp_gpr);

BitSet32 gprs_to_push_early = {};
if (memcheck)
gprs_to_push_early[temp_gpr_index] = true;
if (flags & BackPatchInfo::FLAG_LOAD)
gprs_to_push_early[0] = true;

// If we're already pushing one register in the first PushRegisters call, we can push a
// second one for free. Let's do so, since it might save one instruction in the second
// PushRegisters call. (Do not do this for caller-saved registers which may be in the register
// cache, or else EmitMemcheck will not be able to flush the register cache correctly!)
if (gprs_to_push & gprs_to_push_early)
gprs_to_push_early[30] = true;

ABI_PushRegisters(gprs_to_push & gprs_to_push_early);
ABI_PushRegisters(gprs_to_push & ~gprs_to_push_early);
m_float_emit.ABI_PushRegisters(fprs_to_push, ARM64Reg::X30);

if (flags & BackPatchInfo::FLAG_STORE)
{
const u32 access_size = BackPatchInfo::GetFlagSize(flags);
ARM64Reg src_reg = RS;
const ARM64Reg dst_reg = access_size == 64 ? ARM64Reg::X0 : ARM64Reg::W0;

@@ -185,8 +207,6 @@ void JitArm64::EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, AR
}
else
{
const u32 access_size = BackPatchInfo::GetFlagSize(flags);

if (access_size == 64)
MOVP2R(ARM64Reg::X8, &PowerPC::Read_U64);
else if (access_size == 32)
@@ -197,7 +217,21 @@ void JitArm64::EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, AR
MOVP2R(ARM64Reg::X8, &PowerPC::Read_U8);

BLR(ARM64Reg::X8);
}

m_float_emit.ABI_PopRegisters(fprs_to_push, ARM64Reg::X30);
ABI_PopRegisters(gprs_to_push & ~gprs_to_push_early);

if (memcheck)
{
const ARM64Reg temp_fpr = fprs_to_push[0] ? ARM64Reg::INVALID_REG : ARM64Reg::Q0;
const u64 early_push_size = Common::AlignUp(gprs_to_push_early.Count(), 2) * 8;

WriteConditionalExceptionExit(EXCEPTION_DSI, temp_gpr, temp_fpr, early_push_size);
}

if (flags & BackPatchInfo::FLAG_LOAD)
{
ARM64Reg src_reg = access_size == 64 ? ARM64Reg::X0 : ARM64Reg::W0;

if (flags & BackPatchInfo::FLAG_PAIR)
@@ -221,8 +255,7 @@ void JitArm64::EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, AR
ByteswapAfterLoad(this, &m_float_emit, RS, src_reg, flags, false, false);
}

m_float_emit.ABI_PopRegisters(fprs_to_push, ARM64Reg::X30);
ABI_PopRegisters(gprs_to_push);
ABI_PopRegisters(gprs_to_push & gprs_to_push_early);
}

if (in_far_code)

0 comments on commit d2ca103

Please sign in to comment.