From 1f8217a09b7932bd35dd06ac534e28599a8eb84b Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 3 Apr 2016 13:38:13 +0100 Subject: [PATCH] JitX64: Implement synchronisation instructions --- src/core/CMakeLists.txt | 1 + src/core/arm/decoder/arm.cpp | 21 +- src/core/arm/decoder/decoder.h | 19 +- .../jit_x64/instructions/helper/load_store.h | 76 +++++ .../arm/jit_x64/instructions/load_store.cpp | 111 +------ .../jit_x64/instructions/synchronisation.cpp | 297 +++++++++++++++++- src/core/arm/jit_x64/jit_x64.cpp | 1 - src/core/arm/jit_x64/jit_x64.h | 19 +- 8 files changed, 397 insertions(+), 148 deletions(-) create mode 100644 src/core/arm/jit_x64/instructions/helper/load_store.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 76c9cc629..29275a926 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -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 diff --git a/src/core/arm/decoder/arm.cpp b/src/core/arm/decoder/arm.cpp index 99dd76329..bcbe8ec41 100644 --- a/src/core/arm/decoder/arm.cpp +++ b/src/core/arm/decoder/arm.cpp @@ -114,7 +114,7 @@ static std::unique_ptr MakeMatcher(const char format[32], Function fn) return std::unique_ptr(std::move(ret)); } -static const std::array arm_instruction_table = {{ +static const std::array 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 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) }, diff --git a/src/core/arm/decoder/decoder.h b/src/core/arm/decoder/decoder.h index 51b1218bf..3becf6f76 100644 --- a/src/core/arm/decoder/decoder.h +++ b/src/core/arm/decoder/decoder.h @@ -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; diff --git a/src/core/arm/jit_x64/instructions/helper/load_store.h b/src/core/arm/jit_x64/instructions/helper/load_store.h new file mode 100644 index 000000000..151a5d241 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/helper/load_store.h @@ -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(Memory::Read32(addr + 4)) << 32); +} + +static u64 Load64BE(u32 addr) { + // TODO: Improve this. + return Common::swap32(Memory::Read32(addr)) | (static_cast(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 diff --git a/src/core/arm/jit_x64/instructions/load_store.cpp b/src/core/arm/jit_x64/instructions/load_store.cpp index d74bd2c57..9e0ed4179 100644 --- a/src/core/arm/jit_x64/instructions/load_store.cpp +++ b/src/core/arm/jit_x64/instructions/load_store.cpp @@ -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(Memory::Read32(addr + 4)) << 32); -} - -static u64 Load64BE(u32 addr) { - // TODO: Improve this. - return Common::swap32(Memory::Read32(addr)) | (static_cast(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(!current.EFlag ? &ExecuteSTMLE : &ExecuteSTMBE)); }); - // TODO: Exclusive stuff - current.arm_pc += GetInstSize(); } diff --git a/src/core/arm/jit_x64/instructions/synchronisation.cpp b/src/core/arm/jit_x64/instructions/synchronisation.cpp index f164b28df..a69352b3a 100644 --- a/src/core/arm/jit_x64/instructions/synchronisation.cpp +++ b/src/core/arm/jit_x64/instructions/synchronisation.cpp @@ -2,19 +2,296 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include + +#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(!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(&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(!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(!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 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(!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(&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(!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(!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(); +} } \ No newline at end of file diff --git a/src/core/arm/jit_x64/jit_x64.cpp b/src/core/arm/jit_x64/jit_x64.cpp index be15cfabc..31eec88cd 100644 --- a/src/core/arm/jit_x64/jit_x64.cpp +++ b/src/core/arm/jit_x64/jit_x64.cpp @@ -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) { diff --git a/src/core/arm/jit_x64/jit_x64.h b/src/core/arm/jit_x64/jit_x64.h index 3aef349e5..7997d232f 100644 --- a/src/core/arm/jit_x64/jit_x64.h +++ b/src/core/arm/jit_x64/jit_x64.h @@ -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;