JitX64: Implement synchronisation instructions

This commit is contained in:
MerryMage 2016-04-03 13:38:13 +01:00
parent 8bd590ed99
commit 1f8217a09b
8 changed files with 397 additions and 148 deletions

View File

@ -295,6 +295,7 @@ if(ARCHITECTURE_x86_64)
set(HEADERS ${HEADERS}
arm/jit_x64/common.h
arm/jit_x64/instructions/helper/load_store.h
arm/jit_x64/interface.h
arm/jit_x64/jit_x64.h
arm/jit_x64/reg_alloc.h

View File

@ -114,7 +114,7 @@ static std::unique_ptr<Matcher> MakeMatcher(const char format[32], Function fn)
return std::unique_ptr<Matcher>(std::move(ret));
}
static const std::array<Instruction, 220> arm_instruction_table = {{
static const std::array<Instruction, 221> arm_instruction_table = {{
// Branch instructions
{ "BLX (immediate)", MakeMatcher<2>("1111101hvvvvvvvvvvvvvvvvvvvvvvvv", &Visitor::BLX_imm) }, // ARMv5
{ "BLX (register)", MakeMatcher<2>("cccc000100101111111111110011mmmm", &Visitor::BLX_reg) }, // ARMv5
@ -217,15 +217,16 @@ static const std::array<Instruction, 220> arm_instruction_table = {{
// Synchronization Primitive instructions
{ "CLREX", MakeMatcher<0>("11110101011111111111000000011111", &Visitor::CLREX) }, // ARMv6K
{ "LDREX", MakeMatcher<0>("----00011001--------111110011111", &Visitor::LDREX) }, // ARMv6
{ "LDREXB", MakeMatcher<0>("----00011101--------111110011111", &Visitor::LDREXB) }, // ARMv6K
{ "LDREXD", MakeMatcher<0>("----00011011--------111110011111", &Visitor::LDREXD) }, // ARMv6K
{ "LDREXH", MakeMatcher<0>("----00011111--------111110011111", &Visitor::LDREXH) }, // ARMv6K
{ "STREX", MakeMatcher<0>("----00011000--------11111001----", &Visitor::STREX) }, // ARMv6
{ "STREXB", MakeMatcher<0>("----00011100--------11111001----", &Visitor::STREXB) }, // ARMv6K
{ "STREXD", MakeMatcher<0>("----00011010--------11111001----", &Visitor::STREXD) }, // ARMv6K
{ "STREXH", MakeMatcher<0>("----00011110--------11111001----", &Visitor::STREXH) }, // ARMv6K
{ "SWP", MakeMatcher<0>("----00010-00--------00001001----", &Visitor::SWP) }, // ARMv2S
{ "LDREX", MakeMatcher<3>("cccc00011001nnnndddd111110011111", &Visitor::LDREX) }, // ARMv6
{ "LDREXB", MakeMatcher<3>("cccc00011101nnnndddd111110011111", &Visitor::LDREXB) }, // ARMv6K
{ "LDREXD", MakeMatcher<3>("cccc00011011nnnndddd111110011111", &Visitor::LDREXD) }, // ARMv6K
{ "LDREXH", MakeMatcher<3>("cccc00011111nnnndddd111110011111", &Visitor::LDREXH) }, // ARMv6K
{ "STREX", MakeMatcher<4>("cccc00011000nnnndddd11111001mmmm", &Visitor::STREX) }, // ARMv6
{ "STREXB", MakeMatcher<4>("cccc00011100nnnndddd11111001mmmm", &Visitor::STREXB) }, // ARMv6K
{ "STREXD", MakeMatcher<4>("cccc00011010nnnndddd11111001mmmm", &Visitor::STREXD) }, // ARMv6K
{ "STREXH", MakeMatcher<4>("cccc00011110nnnndddd11111001mmmm", &Visitor::STREXH) }, // ARMv6K
{ "SWP", MakeMatcher<4>("cccc00010000nnnndddd00001001mmmm", &Visitor::SWP) }, // ARMv2S (Deprecated in ARMv6)
{ "SWPB", MakeMatcher<4>("cccc00010100nnnndddd00001001mmmm", &Visitor::SWPB) }, // ARMv2S (Deprecated in ARMv6)
// Load/Store instructions
{ "LDR (imm)", MakeMatcher<7>("cccc010pu0w1nnnnddddvvvvvvvvvvvv", &Visitor::LDR_imm) },

View File

@ -302,15 +302,16 @@ public:
// Synchronization Primitive instructions
virtual void CLREX() = 0;
virtual void LDREX() = 0;
virtual void LDREXB() = 0;
virtual void LDREXD() = 0;
virtual void LDREXH() = 0;
virtual void STREX() = 0;
virtual void STREXB() = 0;
virtual void STREXD() = 0;
virtual void STREXH() = 0;
virtual void SWP() = 0;
virtual void LDREX(Cond cond, Register Rn, Register Rd) = 0;
virtual void LDREXB(Cond cond, Register Rn, Register Rd) = 0;
virtual void LDREXD(Cond cond, Register Rn, Register Rd) = 0;
virtual void LDREXH(Cond cond, Register Rn, Register Rd) = 0;
virtual void STREX(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
virtual void STREXB(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
virtual void STREXD(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
virtual void STREXH(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
virtual void SWP(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
virtual void SWPB(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
// Status register access instructions
virtual void CPS() = 0;

View File

@ -0,0 +1,76 @@
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/common_types.h"
#include "common/swap.h"
#include "core/memory.h"
namespace JitX64 {
// TODO: Set up an appropriately mapped region of memory to use instead of compiling CALL instructions.
constexpr u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
static u64 Load64LE(u32 addr) {
// TODO: Improve this.
return Memory::Read32(addr) | (static_cast<u64>(Memory::Read32(addr + 4)) << 32);
}
static u64 Load64BE(u32 addr) {
// TODO: Improve this.
return Common::swap32(Memory::Read32(addr)) | (static_cast<u64>(Common::swap32(Memory::Read32(addr + 4))) << 32);
}
static void Store64LE(u32 addr, u32 v1, u32 v2) {
Memory::Write32(addr, v1);
Memory::Write32(addr + 4, v2);
}
static void Store64BE(u32 addr, u32 v1, u32 v2) {
Memory::Write32(addr, Common::swap32(v2));
Memory::Write32(addr + 4, Common::swap32(v1));
}
static u32 Load32LE(u32 addr) {
return Memory::Read32(addr);
}
static u32 Load32BE(u32 addr) {
return Common::swap32(Memory::Read32(addr));
}
static void Store32LE(u32 addr, u32 value) {
Memory::Write32(addr, value);
}
static void Store32BE(u32 addr, u32 value) {
Memory::Write32(addr, Common::swap32(value));
}
static u16 Load16LE(u32 addr) {
return Memory::Read16(addr);
}
static u16 Load16BE(u32 addr) {
return Common::swap16(Memory::Read16(addr));
}
static void Store16LE(u32 addr, u16 value) {
Memory::Write16(addr, value);
}
static void Store16BE(u32 addr, u16 value) {
Memory::Write16(addr, Common::swap16(value));
}
static u32 Load8(u32 addr) {
return Memory::Read8(addr);
}
static void Store8(u32 addr, u8 value) {
Memory::Write8(addr, value);
}
} // namespace JitX64

View File

@ -7,11 +7,11 @@
#include "common/x64/abi.h"
#include "core/arm/jit_x64/jit_x64.h"
#include "core/memory.h"
#include "core/arm/jit_x64/instructions/helper/load_store.h"
namespace JitX64 {
// TODO: Loads from constant memory regions can be turned into immediate constant loads.
// TODO: Optimization: Loads from read-only memory regions can be turned into immediate constant loads.
using namespace Gen;
@ -168,68 +168,6 @@ void JitX64::LoadAndStoreWordOrUnsignedByte_ScaledRegisterPostIndexed(X64Reg des
reg_alloc.UnlockArm(Rn_index);
}
// TODO: Set up an appropriately mapped region of memory to use instead of compiling CALL instructions.
static u64 Load64LE(u32 addr) {
// TODO: Improve this.
return Memory::Read32(addr) | (static_cast<u64>(Memory::Read32(addr + 4)) << 32);
}
static u64 Load64BE(u32 addr) {
// TODO: Improve this.
return Common::swap32(Memory::Read32(addr)) | (static_cast<u64>(Common::swap32(Memory::Read32(addr + 4))) << 32);
}
static void Store64LE(u32 addr, u32 v1, u32 v2) {
Memory::Write32(addr, v1);
Memory::Write32(addr + 4, v2);
}
static void Store64BE(u32 addr, u32 v1, u32 v2) {
Memory::Write32(addr, Common::swap32(v1));
Memory::Write32(addr+4, Common::swap32(v2));
}
static u32 Load32LE(u32 addr) {
return Memory::Read32(addr);
}
static u32 Load32BE(u32 addr) {
return Common::swap32(Memory::Read32(addr));
}
static void Store32LE(u32 addr, u32 value) {
Memory::Write32(addr, value);
}
static void Store32BE(u32 addr, u32 value) {
Memory::Write32(addr, Common::swap32(value));
}
static u16 Load16LE(u32 addr) {
return Memory::Read16(addr);
}
static u16 Load16BE(u32 addr) {
return Common::swap16(Memory::Read16(addr));
}
static void Store16LE(u32 addr, u16 value) {
Memory::Write16(addr, value);
}
static void Store16BE(u32 addr, u16 value) {
Memory::Write16(addr, Common::swap16(value));
}
static u32 Load8(u32 addr) {
return Memory::Read8(addr);
}
static void Store8(u32 addr, u8 value) {
Memory::Write8(addr, value);
}
static void GetValueOfRegister(XEmitter* code, RegAlloc& reg_alloc, u32 r15_value, X64Reg x64_reg, ArmReg arm_reg) {
if (arm_reg != 15) {
OpArg Rd = reg_alloc.LockArmForRead(arm_reg);
@ -389,9 +327,6 @@ void JitX64::LDRB_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
}
void JitX64::STR_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm12 imm12) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
// Rd_index == R15 is IMPLEMENTATION DEFINED
@ -414,15 +349,10 @@ void JitX64::STR_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.UnlockX64(ABI_PARAM1);
reg_alloc.UnlockX64(ABI_PARAM2);
// TODO: Exclusive stuff
current.arm_pc += GetInstSize();
}
void JitX64::STR_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm_index) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
// Rd_index == R15 is IMPLEMENTATION DEFINED
@ -445,15 +375,10 @@ void JitX64::STR_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.UnlockX64(ABI_PARAM1);
reg_alloc.UnlockX64(ABI_PARAM2);
// TODO: Exclusive stuff
current.arm_pc += GetInstSize();
}
void JitX64::STRB_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm12 imm12) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rd_index != 15, "UNPREDICTABLE");
@ -476,15 +401,10 @@ void JitX64::STRB_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.UnlockX64(ABI_PARAM1);
reg_alloc.UnlockX64(ABI_PARAM2);
//TODO: Exclusive stuff
current.arm_pc += GetInstSize();
}
void JitX64::STRB_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm_index) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rd_index != 15, "UNPREDICTABLE");
@ -507,8 +427,6 @@ void JitX64::STRB_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.UnlockX64(ABI_PARAM1);
reg_alloc.UnlockX64(ABI_PARAM2);
//TODO: Exclusive stuff
current.arm_pc += GetInstSize();
}
@ -771,9 +689,6 @@ void JitX64::LDRSH_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmRe
}
void JitX64::STRD_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm4 imm8a, ArmImm4 imm8b) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rd_index < 14, "UNPREDICTABLE");
@ -799,15 +714,10 @@ void JitX64::STRD_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.UnlockX64(ABI_PARAM2);
reg_alloc.UnlockX64(ABI_PARAM3);
// TODO: Exclusive stuff.
current.arm_pc += GetInstSize();
}
void JitX64::STRD_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rd_index < 14, "UNPREDICTABLE");
@ -835,15 +745,10 @@ void JitX64::STRD_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.UnlockX64(ABI_PARAM2);
reg_alloc.UnlockX64(ABI_PARAM3);
// TODO: Exclusive stuff.
current.arm_pc += GetInstSize();
}
void JitX64::STRH_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm4 imm8a, ArmImm4 imm8b) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rd_index != 15, "UNPREDICTABLE");
@ -866,15 +771,10 @@ void JitX64::STRH_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.UnlockX64(ABI_PARAM1);
reg_alloc.UnlockX64(ABI_PARAM2);
// TODO: Exclusive stuff.
current.arm_pc += GetInstSize();
}
void JitX64::STRH_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rd_index != 15, "UNPREDICTABLE");
@ -897,8 +797,6 @@ void JitX64::STRH_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
reg_alloc.UnlockX64(ABI_PARAM1);
reg_alloc.UnlockX64(ABI_PARAM2);
// TODO: Exclusive stuff.
current.arm_pc += GetInstSize();
}
@ -1114,9 +1012,6 @@ static void ExecuteSTMBE(u32 start_address, u16 reg_list, JitState* jit_state) {
}
void JitX64::STM(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmRegList list) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rn_index != 15, "UNPREDICTABLE");
@ -1129,8 +1024,6 @@ void JitX64::STM(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmRegList
LoadAndStoreMultiple_Helper(code, reg_alloc, P, U, W, Rn_index, list,
[this](){ CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? &ExecuteSTMLE : &ExecuteSTMBE)); });
// TODO: Exclusive stuff
current.arm_pc += GetInstSize();
}

View File

@ -2,19 +2,296 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <functional>
#include "common/assert.h"
#include "common/x64/abi.h"
#include "core/arm/jit_x64/jit_x64.h"
#include "core/arm/jit_x64/instructions/helper/load_store.h"
namespace JitX64 {
void JitX64::CLREX() { CompileInterpretInstruction(); }
void JitX64::LDREX() { CompileInterpretInstruction(); }
void JitX64::LDREXB() { CompileInterpretInstruction(); }
void JitX64::LDREXD() { CompileInterpretInstruction(); }
void JitX64::LDREXH() { CompileInterpretInstruction(); }
void JitX64::STREX() { CompileInterpretInstruction(); }
void JitX64::STREXB() { CompileInterpretInstruction(); }
void JitX64::STREXD() { CompileInterpretInstruction(); }
void JitX64::STREXH() { CompileInterpretInstruction(); }
void JitX64::SWP() { CompileInterpretInstruction(); }
using namespace Gen;
void JitX64::CLREX() {
cond_manager.Always();
code->MOV(32, MJitStateExclusiveTag(), Imm32(0xFFFFFFFF));
code->MOV(8, MJitStateExclusiveState(), Imm8(0));
current.arm_pc += GetInstSize();
}
void ExclusiveLoadCommon(XEmitter* code, RegAlloc& reg_alloc, OpArg exclusive_state, OpArg exclusive_tag, ArmReg Rn_index, ArmReg Rd_index) {
ASSERT_MSG(Rn_index != 15 && Rd_index != 15, "UNPREDICTABLE");
code->MOV(8, exclusive_state, Imm8(1));
reg_alloc.FlushX64(ABI_PARAM1);
reg_alloc.LockX64(ABI_PARAM1);
OpArg Rn = reg_alloc.LockArmForRead(Rn_index);
code->MOV(32, R(ABI_PARAM1), Rn);
reg_alloc.UnlockArm(Rn_index);
code->MOV(32, exclusive_tag, R(ABI_PARAM1));
code->AND(32, exclusive_tag, Imm32(RESERVATION_GRANULE_MASK));
reg_alloc.UnlockX64(ABI_PARAM1);
}
void JitX64::LDREX(Cond cond, ArmReg Rn_index, ArmReg Rd_index) {
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rn_index != 15 && Rd_index != 15, "UNPREDICTABLE");
ExclusiveLoadCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(), Rn_index, Rd_index);
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? &Load32LE : &Load32BE));
reg_alloc.LockX64(ABI_RETURN);
X64Reg Rd = reg_alloc.BindArmForWrite(Rd_index);
code->MOV(32, R(Rd), R(ABI_RETURN));
reg_alloc.UnlockArm(Rd_index);
reg_alloc.UnlockX64(ABI_RETURN);
current.arm_pc += GetInstSize();
}
void JitX64::LDREXB(Cond cond, ArmReg Rn_index, ArmReg Rd_index) {
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rn_index != 15 && Rd_index != 15, "UNPREDICTABLE");
ExclusiveLoadCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(), Rn_index, Rd_index);
CompileCallHost(reinterpret_cast<const void* const>(&Load8));
reg_alloc.LockX64(ABI_RETURN);
X64Reg Rd = reg_alloc.BindArmForWrite(Rd_index);
code->MOVZX(32, 8, Rd, R(ABI_RETURN));
reg_alloc.UnlockArm(Rd_index);
reg_alloc.UnlockX64(ABI_RETURN);
current.arm_pc += GetInstSize();
}
void JitX64::LDREXD(Cond cond, ArmReg Rn_index, ArmReg Rd_index) {
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rd_index % 2 == 0, "UNPREDICTABLE");
ASSERT_MSG(Rd_index < 14, "UNPREDICTABLE");
ASSERT_MSG(Rn_index != 15, "UNPREDICTABLE");
ExclusiveLoadCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(), Rn_index, Rd_index);
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? Load64LE : Load64BE));
reg_alloc.LockX64(ABI_RETURN);
X64Reg Rd0 = reg_alloc.BindArmForWrite(Rd_index + 0);
X64Reg Rd1 = reg_alloc.BindArmForWrite(Rd_index + 1);
code->MOV(64, R(Rd0), R(ABI_RETURN));
code->SHR(64, R(ABI_RETURN), Imm8(32));
code->MOV(32, R(Rd1), R(ABI_RETURN));
reg_alloc.UnlockArm(Rd_index + 0);
reg_alloc.UnlockArm(Rd_index + 1);
reg_alloc.UnlockX64(ABI_RETURN);
current.arm_pc += GetInstSize();
}
void JitX64::LDREXH(Cond cond, ArmReg Rn_index, ArmReg Rd_index) {
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rn_index != 15 && Rd_index != 15, "UNPREDICTABLE");
ExclusiveLoadCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(), Rn_index, Rd_index);
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? Load16LE : Load16BE));
reg_alloc.LockX64(ABI_RETURN);
X64Reg Rd = reg_alloc.BindArmForWrite(Rd_index);
code->MOVZX(32, 16, Rd, R(ABI_RETURN));
reg_alloc.UnlockArm(Rd_index);
reg_alloc.UnlockX64(ABI_RETURN);
current.arm_pc += GetInstSize();
}
void ExclusiveStoreCommon(XEmitter* code, RegAlloc& reg_alloc, OpArg exclusive_state, OpArg exclusive_tag, ArmReg Rn_index, ArmReg Rd_index, std::function<void()> do_memory_access) {
OpArg Rn = reg_alloc.LockArmForRead(Rn_index);
OpArg Rd = reg_alloc.LockArmForWrite(Rd_index);
code->MOV(32, Rd, Imm8(1)); // First, assume we failed.
code->MOV(32, R(ABI_PARAM1), Rn);
code->BT(8, exclusive_state, Imm8(0));
auto jmp_to_end1 = code->J_CC(CC_NC);
code->MOV(32, R(ABI_PARAM2), R(ABI_PARAM1));
code->AND(32, R(ABI_PARAM2), Imm32(RESERVATION_GRANULE_MASK));
code->CMP(32, R(ABI_PARAM2), exclusive_tag);
auto jmp_to_end2 = code->J_CC(CC_NE);
// Exclsuive monitor pass
code->MOV(32, Rd, Imm8(0)); // Okay, actually we passed.
code->MOV(8, exclusive_state, Imm8(0)); // Unset exclusive memory acecss.
code->MOV(32, exclusive_tag, Imm32(0xFFFFFFFF)); // Unset exclusive memory acecss.
do_memory_access();
code->SetJumpTarget(jmp_to_end1);
code->SetJumpTarget(jmp_to_end2);
reg_alloc.UnlockArm(Rd_index);
reg_alloc.UnlockArm(Rn_index);
}
void JitX64::STREX(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rn_index != 15 && Rd_index != 15 && Rm_index != 15, "UNPREDICTABLE");
ASSERT_MSG(Rd_index != Rn_index && Rd_index != Rm_index, "UNPREDICTABLE");
reg_alloc.FlushX64(ABI_PARAM1);
reg_alloc.LockX64(ABI_PARAM1);
reg_alloc.FlushX64(ABI_PARAM2);
reg_alloc.LockX64(ABI_PARAM2);
OpArg Rm = reg_alloc.LockArmForRead(Rm_index);
ExclusiveStoreCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(),
Rn_index, Rd_index,
[&](){
code->MOV(32, R(ABI_PARAM2), Rm);
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? &Store32LE : &Store32BE));
});
reg_alloc.UnlockArm(Rm_index);
reg_alloc.UnlockX64(ABI_PARAM2);
reg_alloc.UnlockX64(ABI_PARAM1);
current.arm_pc += GetInstSize();
}
void JitX64::STREXB(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rn_index != 15 && Rd_index != 15 && Rm_index != 15, "UNPREDICTABLE");
ASSERT_MSG(Rd_index != Rn_index && Rd_index != Rm_index, "UNPREDICTABLE");
reg_alloc.FlushX64(ABI_PARAM1);
reg_alloc.LockX64(ABI_PARAM1);
reg_alloc.FlushX64(ABI_PARAM2);
reg_alloc.LockX64(ABI_PARAM2);
OpArg Rm = reg_alloc.LockArmForRead(Rm_index);
ExclusiveStoreCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(),
Rn_index, Rd_index,
[&]() {
code->MOV(32, R(ABI_PARAM2), Rm);
CompileCallHost(reinterpret_cast<const void* const>(&Store8));
});
reg_alloc.UnlockArm(Rm_index);
reg_alloc.UnlockX64(ABI_PARAM2);
reg_alloc.UnlockX64(ABI_PARAM1);
current.arm_pc += GetInstSize();
}
void JitX64::STREXD(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rn_index != 15 && Rd_index != 15 && Rm_index != 15, "UNPREDICTABLE");
ASSERT_MSG(Rm_index != 14, "UNPREDICTABLE");
ASSERT_MSG(Rd_index != Rn_index && Rd_index != Rm_index, "UNPREDICTABLE");
ASSERT_MSG(Rd_index != Rm_index + 1, "UNPREDICTABLE");
ASSERT_MSG(Rm_index % 2 == 0, "UNPREDICTABLE");
reg_alloc.FlushX64(ABI_PARAM1);
reg_alloc.LockX64(ABI_PARAM1);
reg_alloc.FlushX64(ABI_PARAM2);
reg_alloc.LockX64(ABI_PARAM2);
reg_alloc.FlushX64(ABI_PARAM3);
reg_alloc.LockX64(ABI_PARAM3);
OpArg Rm0 = reg_alloc.LockArmForRead(Rm_index + 0);
OpArg Rm1 = reg_alloc.LockArmForRead(Rm_index + 1);
ExclusiveStoreCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(),
Rn_index, Rd_index,
[&]() {
code->MOV(32, R(ABI_PARAM2), Rm0);
code->MOV(32, R(ABI_PARAM3), Rm1);
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? &Store64LE : &Store64BE));
});
reg_alloc.UnlockArm(Rm_index + 1);
reg_alloc.UnlockArm(Rm_index + 0);
reg_alloc.UnlockX64(ABI_PARAM3);
reg_alloc.UnlockX64(ABI_PARAM2);
reg_alloc.UnlockX64(ABI_PARAM1);
current.arm_pc += GetInstSize();
}
void JitX64::STREXH(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
CompileInterpretInstruction();
return;
cond_manager.CompileCond((ConditionCode)cond);
ASSERT_MSG(Rn_index != 15 && Rd_index != 15 && Rm_index != 15, "UNPREDICTABLE");
ASSERT_MSG(Rd_index != Rn_index && Rd_index != Rm_index, "UNPREDICTABLE");
reg_alloc.FlushX64(ABI_PARAM1);
reg_alloc.LockX64(ABI_PARAM1);
reg_alloc.FlushX64(ABI_PARAM2);
reg_alloc.LockX64(ABI_PARAM2);
OpArg Rm = reg_alloc.LockArmForRead(Rm_index);
ExclusiveStoreCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(),
Rn_index, Rd_index,
[&]() {
code->MOV(32, R(ABI_PARAM2), Rm);
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? &Store16LE : &Store16BE));
});
reg_alloc.UnlockArm(Rm_index);
reg_alloc.UnlockX64(ABI_PARAM2);
reg_alloc.UnlockX64(ABI_PARAM1);
current.arm_pc += GetInstSize();
}
void JitX64::SWP(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
CompileInterpretInstruction();
}
void JitX64::SWPB(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
CompileInterpretInstruction();
}
}

View File

@ -51,7 +51,6 @@ CodePtr JitX64::Compile(u32 pc, bool TFlag, bool EFlag) {
}
reg_alloc.AssertNoLocked();
reg_alloc.FlushEverything();
} while (!stop_compilation && ((current.arm_pc & 0xFFF) != 0));
if (!stop_compilation) {

View File

@ -399,15 +399,16 @@ private:
// Synchronization Primitive instructions
void CLREX() override;
void LDREX() override;
void LDREXB() override;
void LDREXD() override;
void LDREXH() override;
void STREX() override;
void STREXB() override;
void STREXD() override;
void STREXH() override;
void SWP() override;
void LDREX(Cond cond, ArmReg Rn, ArmReg Rd) override;
void LDREXB(Cond cond, ArmReg Rn, ArmReg Rd) override;
void LDREXD(Cond cond, ArmReg Rn, ArmReg Rd) override;
void LDREXH(Cond cond, ArmReg Rn, ArmReg Rd) override;
void STREX(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
void STREXB(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
void STREXD(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
void STREXH(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
void SWP(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
void SWPB(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
// Status register access instructions
void CPS() override;