[AArch64] Add floating point backpatching support.

This commit is contained in:
Ryan Houdek 2015-01-07 14:38:14 -06:00
parent f1443bec1e
commit 3fe0b5b969
1 changed files with 167 additions and 4 deletions

View File

@ -29,7 +29,8 @@ static void DoBacktrace(uintptr_t access_address, SContext* ctx)
for (u64 pc = (ctx->CTX_PC - 32); pc < (ctx->CTX_PC + 32); pc += 16) for (u64 pc = (ctx->CTX_PC - 32); pc < (ctx->CTX_PC + 32); pc += 16)
{ {
pc_memory += StringFromFormat("%08x%08x%08x%08x", pc_memory += StringFromFormat("%08x%08x%08x%08x",
*(u32*)pc, *(u32*)(pc + 4), *(u32*)(pc + 8), *(u32*)(pc + 12)); Common::swap32(*(u32*)pc), Common::swap32(*(u32*)(pc + 4)),
Common::swap32(*(u32*)(pc + 8)), Common::swap32(*(u32*)(pc + 12)));
ERROR_LOG(DYNA_REC, "0x%016lx: %08x %08x %08x %08x", ERROR_LOG(DYNA_REC, "0x%016lx: %08x %08x %08x %08x",
pc, *(u32*)pc, *(u32*)(pc + 4), *(u32*)(pc + 8), *(u32*)(pc + 12)); pc, *(u32*)pc, *(u32*)(pc + 4), *(u32*)(pc + 8), *(u32*)(pc + 12));
@ -51,10 +52,34 @@ bool JitArm64::DisasmLoadStore(const u8* ptr, u32* flags, ARM64Reg* reg)
*flags |= BackPatchInfo::FLAG_SIZE_8; *flags |= BackPatchInfo::FLAG_SIZE_8;
else if (size == 1) // 16-bit else if (size == 1) // 16-bit
*flags |= BackPatchInfo::FLAG_SIZE_16; *flags |= BackPatchInfo::FLAG_SIZE_16;
else // 32-bit else if (size == 2) // 32-bit
*flags |= BackPatchInfo::FLAG_SIZE_32; *flags |= BackPatchInfo::FLAG_SIZE_32;
else if (size == 3) // 64-bit
*flags |= BackPatchInfo::FLAG_SIZE_F64;
if (op == 0xE5) // Load if (op == 0xF5) // NEON LDR
{
if (size == 2) // 32-bit float
{
*flags &= ~BackPatchInfo::FLAG_SIZE_32;
*flags |= BackPatchInfo::FLAG_SIZE_F32;
}
*flags |= BackPatchInfo::FLAG_LOAD;
*reg = (ARM64Reg)(inst & 0x1F);
return true;
}
else if (op == 0xF4) // NEON STR
{
if (size == 2) // 32-bit float
{
*flags &= ~BackPatchInfo::FLAG_SIZE_32;
*flags |= BackPatchInfo::FLAG_SIZE_F32;
}
*flags |= BackPatchInfo::FLAG_STORE;
*reg = (ARM64Reg)(inst & 0x1F);
return true;
}
else if (op == 0xE5) // Load
{ {
*flags |= BackPatchInfo::FLAG_LOAD; *flags |= BackPatchInfo::FLAG_LOAD;
*reg = (ARM64Reg)(inst & 0x1F); *reg = (ARM64Reg)(inst & 0x1F);
@ -90,10 +115,38 @@ u32 JitArm64::EmitBackpatchRoutine(ARM64XEmitter* emit, u32 flags, bool fastmem,
if (flags & BackPatchInfo::FLAG_STORE && if (flags & BackPatchInfo::FLAG_STORE &&
flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64)) flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64))
{ {
ARM64FloatEmitter float_emit(emit);
if (flags & BackPatchInfo::FLAG_SIZE_F32)
{
float_emit.FCVT(32, 64, Q0, RS);
float_emit.REV32(8, D0, D0);
trouble_offset = (emit->GetCodePtr() - code_base) / 4;
float_emit.STR(32, INDEX_UNSIGNED, D0, addr, 0);
}
else
{
float_emit.REV64(8, Q0, RS);
trouble_offset = (emit->GetCodePtr() - code_base) / 4;
float_emit.STR(64, INDEX_UNSIGNED, Q0, addr, 0);
}
} }
else if (flags & BackPatchInfo::FLAG_LOAD && else if (flags & BackPatchInfo::FLAG_LOAD &&
flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64)) flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64))
{ {
ARM64FloatEmitter float_emit(emit);
trouble_offset = (emit->GetCodePtr() - code_base) / 4;
if (flags & BackPatchInfo::FLAG_SIZE_F32)
{
float_emit.LD1R(32, RS, addr);
float_emit.REV64(8, RS, RS);
float_emit.FCVTL(64, RS, RS);
}
else
{
float_emit.LDR(64, INDEX_UNSIGNED, Q0, addr, 0);
float_emit.REV64(8, Q0, Q0);
float_emit.INS(64, RS, 0, Q0, 0);
}
} }
else if (flags & BackPatchInfo::FLAG_STORE) else if (flags & BackPatchInfo::FLAG_STORE)
{ {
@ -143,10 +196,39 @@ u32 JitArm64::EmitBackpatchRoutine(ARM64XEmitter* emit, u32 flags, bool fastmem,
if (flags & BackPatchInfo::FLAG_STORE && if (flags & BackPatchInfo::FLAG_STORE &&
flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64)) flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64))
{ {
ARM64FloatEmitter float_emit(emit);
if (flags & BackPatchInfo::FLAG_SIZE_F32)
{
float_emit.FCVT(32, 64, Q0, RS);
float_emit.FMOV(32, false, W0, Q0);
emit->MOVI2R(X30, (u64)&Memory::Write_U32);
emit->BLR(X30);
}
else
{
emit->MOVI2R(X30, (u64)&Memory::Write_F64);
float_emit.DUP(64, Q0, RS);
emit->BLR(X30);
}
} }
else if (flags & BackPatchInfo::FLAG_LOAD && else if (flags & BackPatchInfo::FLAG_LOAD &&
flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64)) flags & (BackPatchInfo::FLAG_SIZE_F32 | BackPatchInfo::FLAG_SIZE_F64))
{ {
ARM64FloatEmitter float_emit(emit);
if (flags & BackPatchInfo::FLAG_SIZE_F32)
{
emit->MOVI2R(X30, (u64)&Memory::Read_U32);
emit->BLR(X30);
float_emit.DUP(32, RS, X0);
float_emit.FCVTL(64, RS, RS);
}
else
{
emit->MOVI2R(X30, (u64)&Memory::Read_F64);
emit->BLR(X30);
float_emit.INS(64, RS, 0, X0);
}
} }
else if (flags & BackPatchInfo::FLAG_STORE) else if (flags & BackPatchInfo::FLAG_STORE)
{ {
@ -245,7 +327,8 @@ bool JitArm64::HandleFault(uintptr_t access_address, SContext* ctx)
ctx->CTX_PC = new_pc; ctx->CTX_PC = new_pc;
// Wipe the top bits of the addr_register // Wipe the top bits of the addr_register
if (flags & BackPatchInfo::FLAG_STORE) if (flags & BackPatchInfo::FLAG_STORE &&
!(flags & BackPatchInfo::FLAG_SIZE_F64))
ctx->CTX_REG(1) &= 0xFFFFFFFFUll; ctx->CTX_REG(1) &= 0xFFFFFFFFUll;
else else
ctx->CTX_REG(0) &= 0xFFFFFFFFUll; ctx->CTX_REG(0) &= 0xFFFFFFFFUll;
@ -382,6 +465,46 @@ void JitArm64::InitBackpatch()
SetCodePtr(code_base); SetCodePtr(code_base);
m_backpatch_info[flags] = info;
}
// 32bit float
{
flags =
BackPatchInfo::FLAG_LOAD |
BackPatchInfo::FLAG_SIZE_F32;
EmitBackpatchRoutine(this, flags, false, false, Q0, X1);
code_end = GetWritableCodePtr();
info.m_slowmem_size = (code_end - code_base) / 4;
SetCodePtr(code_base);
info.m_fastmem_trouble_inst_offset =
EmitBackpatchRoutine(this, flags, true, false, Q0, X1);
code_end = GetWritableCodePtr();
info.m_fastmem_size = (code_end - code_base) / 4;
SetCodePtr(code_base);
m_backpatch_info[flags] = info;
}
// 64bit float
{
flags =
BackPatchInfo::FLAG_LOAD |
BackPatchInfo::FLAG_SIZE_F64;
EmitBackpatchRoutine(this, flags, false, false, Q0, X1);
code_end = GetWritableCodePtr();
info.m_slowmem_size = (code_end - code_base) / 4;
SetCodePtr(code_base);
info.m_fastmem_trouble_inst_offset =
EmitBackpatchRoutine(this, flags, true, false, Q0, X1);
code_end = GetWritableCodePtr();
info.m_fastmem_size = (code_end - code_base) / 4;
SetCodePtr(code_base);
m_backpatch_info[flags] = info; m_backpatch_info[flags] = info;
} }
} }
@ -446,6 +569,46 @@ void JitArm64::InitBackpatch()
SetCodePtr(code_base); SetCodePtr(code_base);
m_backpatch_info[flags] = info;
}
// 32bit float
{
flags =
BackPatchInfo::FLAG_STORE |
BackPatchInfo::FLAG_SIZE_F32;
EmitBackpatchRoutine(this, flags, false, false, Q0, X1);
code_end = GetWritableCodePtr();
info.m_slowmem_size = (code_end - code_base) / 4;
SetCodePtr(code_base);
info.m_fastmem_trouble_inst_offset =
EmitBackpatchRoutine(this, flags, true, false, Q0, X1);
code_end = GetWritableCodePtr();
info.m_fastmem_size = (code_end - code_base) / 4;
SetCodePtr(code_base);
m_backpatch_info[flags] = info;
}
// 64bit float
{
flags =
BackPatchInfo::FLAG_STORE |
BackPatchInfo::FLAG_SIZE_F64;
EmitBackpatchRoutine(this, flags, false, false, Q0, X1);
code_end = GetWritableCodePtr();
info.m_slowmem_size = (code_end - code_base) / 4;
SetCodePtr(code_base);
info.m_fastmem_trouble_inst_offset =
EmitBackpatchRoutine(this, flags, true, false, Q0, X1);
code_end = GetWritableCodePtr();
info.m_fastmem_size = (code_end - code_base) / 4;
SetCodePtr(code_base);
m_backpatch_info[flags] = info; m_backpatch_info[flags] = info;
} }
} }