From 94237b694be82b784ce06c7d921822c145890611 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 17 Dec 2016 20:02:20 -0500 Subject: [PATCH] Jit64Common: Split Jit64Util contents into separate files Much of Jit64Util consists of essentials, not utilities. Breaking these out into their own files also prevents unrelated includes from being present near other classes. This also makes it easier to find and change certain components of the x86-64 JIT, should it be necessary. --- Source/Core/Core/CMakeLists.txt | 3 +- Source/Core/Core/Core.vcxproj | 8 +- Source/Core/Core/Core.vcxproj.filters | 20 +- .../Core/Core/PowerPC/CachedInterpreter.cpp | 2 +- Source/Core/Core/PowerPC/Jit64/Jit.cpp | 4 +- Source/Core/Core/PowerPC/Jit64/JitAsm.cpp | 1 + .../Core/Core/PowerPC/Jit64/JitRegCache.cpp | 2 +- Source/Core/Core/PowerPC/Jit64/Jit_Branch.cpp | 1 + .../Core/PowerPC/Jit64/Jit_FloatingPoint.cpp | 1 + .../Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 3 +- .../Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp | 1 - .../PowerPC/Jit64/Jit_LoadStoreFloating.cpp | 2 +- .../PowerPC/Jit64/Jit_LoadStorePaired.cpp | 2 +- .../PowerPC/Jit64/Jit_SystemRegisters.cpp | 3 +- .../{Jit64Util.cpp => EmuCodeBlock.cpp} | 383 ++++++++++-------- .../{Jit64Util.h => EmuCodeBlock.h} | 125 +----- .../Core/PowerPC/Jit64Common/FarCodeCache.cpp | 22 + .../Core/PowerPC/Jit64Common/FarCodeCache.h | 26 ++ .../PowerPC/Jit64Common/Jit64AsmCommon.cpp | 3 +- .../Core/PowerPC/Jit64Common/Jit64AsmCommon.h | 2 +- .../Core/Core/PowerPC/Jit64Common/Jit64Base.h | 2 + .../PowerPC/Jit64Common/Jit64PowerPCState.h | 19 + .../PowerPC/Jit64Common/TrampolineCache.cpp | 3 +- .../PowerPC/Jit64Common/TrampolineCache.h | 9 +- .../Core/PowerPC/Jit64Common/TrampolineInfo.h | 50 +++ Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp | 1 + Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp | 1 + .../JitILCommon/JitILBase_LoadStorePaired.cpp | 2 + 28 files changed, 395 insertions(+), 306 deletions(-) rename Source/Core/Core/PowerPC/Jit64Common/{Jit64Util.cpp => EmuCodeBlock.cpp} (95%) rename Source/Core/Core/PowerPC/Jit64Common/{Jit64Util.h => EmuCodeBlock.h} (59%) create mode 100644 Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.cpp create mode 100644 Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.h create mode 100644 Source/Core/Core/PowerPC/Jit64Common/Jit64PowerPCState.h create mode 100644 Source/Core/Core/PowerPC/Jit64Common/TrampolineInfo.h diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 0072c57254..63a8436f67 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -207,9 +207,10 @@ if(_M_X86) PowerPC/Jit64/JitRegCache.cpp PowerPC/Jit64/Jit_SystemRegisters.cpp PowerPC/Jit64Common/BlockCache.cpp + PowerPC/Jit64Common/EmuCodeBlock.cpp + PowerPC/Jit64Common/FarCodeCache.cpp PowerPC/Jit64Common/Jit64AsmCommon.cpp PowerPC/Jit64Common/Jit64Base.cpp - PowerPC/Jit64Common/Jit64Util.cpp PowerPC/Jit64Common/TrampolineCache.cpp) elseif(_M_ARM_64) set(SRCS ${SRCS} diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index c851e266d4..e0077a2fdd 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -238,9 +238,10 @@ + + - @@ -431,10 +432,13 @@ + + - + + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index a42cc100c7..5d95dab489 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -738,15 +738,18 @@ PowerPC\Jit64Common + + PowerPC\Jit64Common + + + PowerPC\Jit64Common + PowerPC\Jit64Common PowerPC\Jit64Common - - PowerPC\Jit64Common - PowerPC\Jit64Common @@ -1278,18 +1281,27 @@ PowerPC\Jit64Common + + PowerPC\Jit64Common + + + PowerPC\Jit64Common + PowerPC\Jit64Common PowerPC\Jit64Common - + PowerPC\Jit64Common PowerPC\Jit64Common + + PowerPC\Jit64Common + IPC HLE %28IOS/Starlet%29\USB diff --git a/Source/Core/Core/PowerPC/CachedInterpreter.cpp b/Source/Core/Core/PowerPC/CachedInterpreter.cpp index 0173822147..a1f3c7ce08 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter.cpp +++ b/Source/Core/Core/PowerPC/CachedInterpreter.cpp @@ -10,7 +10,7 @@ #include "Core/HLE/HLE.h" #include "Core/HW/CPU.h" #include "Core/PowerPC/Gekko.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" +#include "Core/PowerPC/Jit64Common/Jit64Base.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PowerPC.h" diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 6b88e5ecb2..1f85560234 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -26,7 +26,9 @@ #include "Core/PowerPC/Jit64/Jit64_Tables.h" #include "Core/PowerPC/Jit64/JitAsm.h" #include "Core/PowerPC/Jit64/JitRegCache.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" +#include "Core/PowerPC/Jit64Common/FarCodeCache.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" +#include "Core/PowerPC/Jit64Common/TrampolineCache.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/Profiler.h" diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp index f0e5f2feb0..5e7bc094ae 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp @@ -12,6 +12,7 @@ #include "Core/HW/CPU.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/Jit64/JitAsm.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/PowerPC.h" using namespace Gen; diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp index c3dc984c5d..278d6a126c 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp @@ -14,7 +14,7 @@ #include "Common/x64Emitter.h" #include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/PowerPC.h" using namespace Gen; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Branch.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Branch.cpp index e7ea90f614..abe3d5a11a 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Branch.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Branch.cpp @@ -9,6 +9,7 @@ #include "Core/CoreTiming.h" #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/Jit64/JitRegCache.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PowerPC.h" diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp index 65339e162d..87976954dd 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp @@ -13,6 +13,7 @@ #include "Core/Core.h" #include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PowerPC.h" diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index a8cd8a24d4..8bf3b6c87c 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -6,12 +6,13 @@ #include #include "Common/Assert.h" +#include "Common/CPUDetect.h" #include "Common/CommonTypes.h" #include "Common/MathUtil.h" #include "Common/x64Emitter.h" #include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PowerPC.h" diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp index 973cc856cd..d3c6dfe767 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp @@ -17,7 +17,6 @@ #include "Core/HW/DSP.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/Jit64/JitRegCache.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PowerPC.h" diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp index 2c6d29003f..7b6511a770 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp @@ -7,7 +7,7 @@ #include "Common/CommonTypes.h" #include "Common/x64Emitter.h" #include "Core/PowerPC/Jit64/JitRegCache.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" using namespace Gen; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp index c3f18e8a85..b260de56dc 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp @@ -10,7 +10,7 @@ #include "Common/CommonTypes.h" #include "Common/x64Emitter.h" #include "Core/PowerPC/Jit64/JitRegCache.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/JitCommon/JitAsmCommon.h" #include "Core/PowerPC/PowerPC.h" diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index 2f262540bd..dbb96a8394 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -4,12 +4,13 @@ #include "Core/PowerPC/Jit64/Jit.h" #include "Common/BitSet.h" +#include "Common/CPUDetect.h" #include "Common/CommonTypes.h" #include "Common/x64Emitter.h" #include "Core/CoreTiming.h" #include "Core/HW/ProcessorInterface.h" #include "Core/PowerPC/Jit64/JitRegCache.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/PowerPC.h" using namespace Gen; diff --git a/Source/Core/Core/PowerPC/Jit64Common/Jit64Util.cpp b/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.cpp similarity index 95% rename from Source/Core/Core/PowerPC/Jit64Common/Jit64Util.cpp rename to Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.cpp index 9db6e5b919..0705058e1d 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/Jit64Util.cpp +++ b/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.cpp @@ -1,22 +1,45 @@ -// Copyright 2008 Dolphin Emulator Project +// Copyright 2016 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Core/PowerPC/Jit64Common/Jit64Util.h" -#include "Common/BitSet.h" -#include "Common/CommonTypes.h" +#include "Core/PowerPC/Jit64Common/EmuCodeBlock.h" + +#include "Common/Assert.h" +#include "Common/CPUDetect.h" #include "Common/Intrinsics.h" #include "Common/MathUtil.h" -#include "Common/x64ABI.h" -#include "Common/x64Emitter.h" #include "Core/HW/MMIO.h" #include "Core/HW/Memmap.h" +#include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/Jit64Common/Jit64Base.h" -#include "Core/PowerPC/Jit64Common/TrampolineCache.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/PowerPC.h" using namespace Gen; +namespace +{ +OpArg SwapImmediate(int access_size, const OpArg& reg_value) +{ + if (access_size == 32) + return Imm32(Common::swap32(reg_value.Imm32())); + + if (access_size == 16) + return Imm16(Common::swap16(reg_value.Imm16())); + + return Imm8(reg_value.Imm8()); +} + +OpArg FixImmediate(int access_size, OpArg arg) +{ + if (arg.IsImm()) + { + arg = access_size == 8 ? arg.AsImm8() : access_size == 16 ? arg.AsImm16() : arg.AsImm32(); + } + return arg; +} +} // Anonymous namespace + void EmuCodeBlock::MemoryExceptionCheck() { // TODO: We really should untangle the trampolines, exception handlers and @@ -47,6 +70,49 @@ void EmuCodeBlock::MemoryExceptionCheck() } } +void EmuCodeBlock::SwitchToFarCode() +{ + nearcode = GetWritableCodePtr(); + SetCodePtr(farcode.GetWritableCodePtr()); +} + +void EmuCodeBlock::SwitchToNearCode() +{ + farcode.SetCodePtr(GetWritableCodePtr()); + SetCodePtr(nearcode); +} + +FixupBranch EmuCodeBlock::CheckIfSafeAddress(const OpArg& reg_value, X64Reg reg_addr, + BitSet32 registers_in_use) +{ + registers_in_use[reg_addr] = true; + if (reg_value.IsSimpleReg()) + registers_in_use[reg_value.GetSimpleReg()] = true; + + // Get ourselves a free register; try to pick one that doesn't involve pushing, if we can. + X64Reg scratch = RSCRATCH; + if (!registers_in_use[RSCRATCH]) + scratch = RSCRATCH; + else if (!registers_in_use[RSCRATCH_EXTRA]) + scratch = RSCRATCH_EXTRA; + else + scratch = reg_addr; + + if (scratch == reg_addr) + PUSH(scratch); + else + MOV(32, R(scratch), R(reg_addr)); + + // Perform lookup to see if we can use fast path. + SHR(32, R(scratch), Imm8(PowerPC::BAT_INDEX_SHIFT)); + TEST(32, MScaled(scratch, SCALE_4, PtrOffset(&PowerPC::dbat_table[0])), Imm32(2)); + + if (scratch == reg_addr) + POP(scratch); + + return J_CC(CC_Z, farcode.Enabled()); +} + void EmuCodeBlock::UnsafeLoadRegToReg(X64Reg reg_addr, X64Reg reg_value, int accessSize, s32 offset, bool signExtend) { @@ -63,6 +129,38 @@ void EmuCodeBlock::UnsafeLoadRegToRegNoSwap(X64Reg reg_addr, X64Reg reg_value, i MOVZX(32, accessSize, reg_value, MComplex(RMEM, reg_addr, SCALE_1, offset)); } +void EmuCodeBlock::UnsafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int accessSize, s32 offset, + bool swap, MovInfo* info) +{ + if (info) + { + info->address = GetWritableCodePtr(); + info->nonAtomicSwapStore = false; + } + + OpArg dest = MComplex(RMEM, reg_addr, SCALE_1, offset); + if (reg_value.IsImm()) + { + if (swap) + reg_value = SwapImmediate(accessSize, reg_value); + MOV(accessSize, dest, reg_value); + } + else if (swap) + { + SwapAndStore(accessSize, dest, reg_value.GetSimpleReg(), info); + } + else + { + MOV(accessSize, dest, reg_value); + } +} + +void EmuCodeBlock::UnsafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, + s32 offset, bool swap, Gen::MovInfo* info) +{ + UnsafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, swap, info); +} + bool EmuCodeBlock::UnsafeLoadToReg(X64Reg reg_value, OpArg opAddress, int accessSize, s32 offset, bool signExtend, MovInfo* info) { @@ -104,6 +202,28 @@ bool EmuCodeBlock::UnsafeLoadToReg(X64Reg reg_value, OpArg opAddress, int access return offsetAddedToAddress; } +void EmuCodeBlock::UnsafeWriteGatherPipe(int accessSize) +{ + // No need to protect these, they don't touch any state + // question - should we inline them instead? Pro: Lose a CALL Con: Code bloat + switch (accessSize) + { + case 8: + CALL(jit->GetAsmRoutines()->fifoDirectWrite8); + break; + case 16: + CALL(jit->GetAsmRoutines()->fifoDirectWrite16); + break; + case 32: + CALL(jit->GetAsmRoutines()->fifoDirectWrite32); + break; + case 64: + CALL(jit->GetAsmRoutines()->fifoDirectWrite64); + break; + } + jit->js.fifoBytesSinceCheck += accessSize >> 3; +} + // Visitor that generates code to read a MMIO value. template class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor @@ -212,37 +332,6 @@ void EmuCodeBlock::MMIOLoadToReg(MMIO::Mapping* mmio, Gen::X64Reg reg_value, } } -FixupBranch EmuCodeBlock::CheckIfSafeAddress(const OpArg& reg_value, X64Reg reg_addr, - BitSet32 registers_in_use) -{ - registers_in_use[reg_addr] = true; - if (reg_value.IsSimpleReg()) - registers_in_use[reg_value.GetSimpleReg()] = true; - - // Get ourselves a free register; try to pick one that doesn't involve pushing, if we can. - X64Reg scratch = RSCRATCH; - if (!registers_in_use[RSCRATCH]) - scratch = RSCRATCH; - else if (!registers_in_use[RSCRATCH_EXTRA]) - scratch = RSCRATCH_EXTRA; - else - scratch = reg_addr; - - if (scratch == reg_addr) - PUSH(scratch); - else - MOV(32, R(scratch), R(reg_addr)); - - // Perform lookup to see if we can use fast path. - SHR(32, R(scratch), Imm8(PowerPC::BAT_INDEX_SHIFT)); - TEST(32, MScaled(scratch, SCALE_4, PtrOffset(&PowerPC::dbat_table[0])), Imm32(2)); - - if (scratch == reg_addr) - POP(scratch); - - return J_CC(CC_Z, farcode.Enabled()); -} - void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg& opAddress, int accessSize, s32 offset, BitSet32 registersInUse, bool signExtend, int flags) { @@ -399,119 +488,6 @@ void EmuCodeBlock::SafeLoadToRegImmediate(X64Reg reg_value, u32 address, int acc } } -static OpArg SwapImmediate(int accessSize, const OpArg& reg_value) -{ - if (accessSize == 32) - return Imm32(Common::swap32(reg_value.Imm32())); - else if (accessSize == 16) - return Imm16(Common::swap16(reg_value.Imm16())); - else - return Imm8(reg_value.Imm8()); -} - -void EmuCodeBlock::UnsafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int accessSize, s32 offset, - bool swap, MovInfo* info) -{ - if (info) - { - info->address = GetWritableCodePtr(); - info->nonAtomicSwapStore = false; - } - - OpArg dest = MComplex(RMEM, reg_addr, SCALE_1, offset); - if (reg_value.IsImm()) - { - if (swap) - reg_value = SwapImmediate(accessSize, reg_value); - MOV(accessSize, dest, reg_value); - } - else if (swap) - { - SwapAndStore(accessSize, dest, reg_value.GetSimpleReg(), info); - } - else - { - MOV(accessSize, dest, reg_value); - } -} - -static OpArg FixImmediate(int accessSize, OpArg arg) -{ - if (arg.IsImm()) - { - arg = accessSize == 8 ? arg.AsImm8() : accessSize == 16 ? arg.AsImm16() : arg.AsImm32(); - } - return arg; -} - -void EmuCodeBlock::UnsafeWriteGatherPipe(int accessSize) -{ - // No need to protect these, they don't touch any state - // question - should we inline them instead? Pro: Lose a CALL Con: Code bloat - switch (accessSize) - { - case 8: - CALL(jit->GetAsmRoutines()->fifoDirectWrite8); - break; - case 16: - CALL(jit->GetAsmRoutines()->fifoDirectWrite16); - break; - case 32: - CALL(jit->GetAsmRoutines()->fifoDirectWrite32); - break; - case 64: - CALL(jit->GetAsmRoutines()->fifoDirectWrite64); - break; - } - jit->js.fifoBytesSinceCheck += accessSize >> 3; -} - -bool EmuCodeBlock::WriteToConstAddress(int accessSize, OpArg arg, u32 address, - BitSet32 registersInUse) -{ - arg = FixImmediate(accessSize, arg); - - // If we already know the address through constant folding, we can do some - // fun tricks... - if (jit->jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(address)) - { - if (!arg.IsSimpleReg(RSCRATCH)) - MOV(accessSize, R(RSCRATCH), arg); - - UnsafeWriteGatherPipe(accessSize); - return false; - } - else if (PowerPC::IsOptimizableRAMAddress(address)) - { - WriteToConstRamAddress(accessSize, arg, address); - return false; - } - else - { - // Helps external systems know which instruction triggered the write - MOV(32, PPCSTATE(pc), Imm32(jit->js.compilerPC)); - - ABI_PushRegistersAndAdjustStack(registersInUse, 0); - switch (accessSize) - { - case 64: - ABI_CallFunctionAC(64, PowerPC::Write_U64, arg, address); - break; - case 32: - ABI_CallFunctionAC(32, PowerPC::Write_U32, arg, address); - break; - case 16: - ABI_CallFunctionAC(16, PowerPC::Write_U16, arg, address); - break; - case 8: - ABI_CallFunctionAC(8, PowerPC::Write_U8, arg, address); - break; - } - ABI_PopRegistersAndAdjustStack(registersInUse, 0); - return true; - } -} - void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int accessSize, s32 offset, BitSet32 registersInUse, int flags) { @@ -625,6 +601,63 @@ void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int acces } } +void EmuCodeBlock::SafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, + s32 offset, BitSet32 registersInUse, int flags) +{ + SafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, registersInUse, flags); +} + +bool EmuCodeBlock::WriteClobbersRegValue(int accessSize, bool swap) +{ + return swap && !cpu_info.bMOVBE && accessSize > 8; +} + +bool EmuCodeBlock::WriteToConstAddress(int accessSize, OpArg arg, u32 address, + BitSet32 registersInUse) +{ + arg = FixImmediate(accessSize, arg); + + // If we already know the address through constant folding, we can do some + // fun tricks... + if (jit->jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(address)) + { + if (!arg.IsSimpleReg(RSCRATCH)) + MOV(accessSize, R(RSCRATCH), arg); + + UnsafeWriteGatherPipe(accessSize); + return false; + } + else if (PowerPC::IsOptimizableRAMAddress(address)) + { + WriteToConstRamAddress(accessSize, arg, address); + return false; + } + else + { + // Helps external systems know which instruction triggered the write + MOV(32, PPCSTATE(pc), Imm32(jit->js.compilerPC)); + + ABI_PushRegistersAndAdjustStack(registersInUse, 0); + switch (accessSize) + { + case 64: + ABI_CallFunctionAC(64, PowerPC::Write_U64, arg, address); + break; + case 32: + ABI_CallFunctionAC(32, PowerPC::Write_U32, arg, address); + break; + case 16: + ABI_CallFunctionAC(16, PowerPC::Write_U16, arg, address); + break; + case 8: + ABI_CallFunctionAC(8, PowerPC::Write_U8, arg, address); + break; + } + ABI_PopRegistersAndAdjustStack(registersInUse, 0); + return true; + } +} + void EmuCodeBlock::WriteToConstRamAddress(int accessSize, OpArg arg, u32 address, bool swap) { X64Reg reg; @@ -653,6 +686,30 @@ void EmuCodeBlock::WriteToConstRamAddress(int accessSize, OpArg arg, u32 address MOV(accessSize, MRegSum(RMEM, RSCRATCH2), R(reg)); } +void EmuCodeBlock::JitGetAndClearCAOV(bool oe) +{ + if (oe) + AND(8, PPCSTATE(xer_so_ov), Imm8(~XER_OV_MASK)); // XER.OV = 0 + SHR(8, PPCSTATE(xer_ca), Imm8(1)); // carry = XER.CA, XER.CA = 0 +} + +void EmuCodeBlock::JitSetCA() +{ + MOV(8, PPCSTATE(xer_ca), Imm8(1)); // XER.CA = 1 +} + +// Some testing shows CA is set roughly ~1/3 of the time (relative to clears), so +// branchless calculation of CA is probably faster in general. +void EmuCodeBlock::JitSetCAIf(CCFlags conditionCode) +{ + SETcc(conditionCode, PPCSTATE(xer_ca)); +} + +void EmuCodeBlock::JitClearCA() +{ + MOV(8, PPCSTATE(xer_ca), Imm8(0)); +} + void EmuCodeBlock::ForceSinglePrecision(X64Reg output, const OpArg& input, bool packed, bool duplicate) { @@ -1083,30 +1140,6 @@ void EmuCodeBlock::SetFPRF(Gen::X64Reg xmm) OR(32, PPCSTATE(fpscr), R(RSCRATCH)); } -void EmuCodeBlock::JitGetAndClearCAOV(bool oe) -{ - if (oe) - AND(8, PPCSTATE(xer_so_ov), Imm8(~XER_OV_MASK)); // XER.OV = 0 - SHR(8, PPCSTATE(xer_ca), Imm8(1)); // carry = XER.CA, XER.CA = 0 -} - -void EmuCodeBlock::JitSetCA() -{ - MOV(8, PPCSTATE(xer_ca), Imm8(1)); // XER.CA = 1 -} - -// Some testing shows CA is set roughly ~1/3 of the time (relative to clears), so -// branchless calculation of CA is probably faster in general. -void EmuCodeBlock::JitSetCAIf(CCFlags conditionCode) -{ - SETcc(conditionCode, PPCSTATE(xer_ca)); -} - -void EmuCodeBlock::JitClearCA() -{ - MOV(8, PPCSTATE(xer_ca), Imm8(0)); -} - void EmuCodeBlock::Clear() { backPatchInfo.clear(); diff --git a/Source/Core/Core/PowerPC/Jit64Common/Jit64Util.h b/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.h similarity index 59% rename from Source/Core/Core/PowerPC/Jit64Common/Jit64Util.h rename to Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.h index 15269c2d1a..066d6b446d 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/Jit64Util.h +++ b/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.h @@ -1,106 +1,23 @@ -// Copyright 2010 Dolphin Emulator Project +// Copyright 2016 Dolphin Emulator Project // Licensed under GPLv2+ -// Refer to the license.txt file included./ +// Refer to the license.txt file included. #pragma once #include #include "Common/BitSet.h" -#include "Common/CPUDetect.h" #include "Common/CommonTypes.h" #include "Common/x64Emitter.h" -#include "Core/PowerPC/PowerPC.h" + +#include "Core/PowerPC/Jit64Common/FarCodeCache.h" +#include "Core/PowerPC/Jit64Common/TrampolineInfo.h" namespace MMIO { class Mapping; } -// We offset by 0x80 because the range of one byte memory offsets is -// -0x80..0x7f. -#define PPCSTATE(x) \ - MDisp(RPPCSTATE, (int)((char*)&PowerPC::ppcState.x - (char*)&PowerPC::ppcState) - 0x80) -// In case you want to disable the ppcstate register: -// #define PPCSTATE(x) M(&PowerPC::ppcState.x) -#define PPCSTATE_LR PPCSTATE(spr[SPR_LR]) -#define PPCSTATE_CTR PPCSTATE(spr[SPR_CTR]) -#define PPCSTATE_SRR0 PPCSTATE(spr[SPR_SRR0]) -#define PPCSTATE_SRR1 PPCSTATE(spr[SPR_SRR1]) - -// A place to throw blocks of code we don't want polluting the cache, e.g. rarely taken -// exception branches. -class FarCodeCache : public Gen::X64CodeBlock -{ -private: - bool m_enabled = false; - -public: - bool Enabled() const { return m_enabled; } - void Init(int size) - { - AllocCodeSpace(size); - m_enabled = true; - } - void Shutdown() - { - FreeCodeSpace(); - m_enabled = false; - } -}; - -constexpr int CODE_SIZE = 1024 * 1024 * 32; - -// a bit of a hack; the MMU results in a vast amount more code ending up in the far cache, -// mostly exception handling, so give it a whole bunch more space if the MMU is on. -constexpr int FARCODE_SIZE = 1024 * 1024 * 8; -constexpr int FARCODE_SIZE_MMU = 1024 * 1024 * 48; - -// same for the trampoline code cache, because fastmem results in far more backpatches in MMU mode -constexpr int TRAMPOLINE_CODE_SIZE = 1024 * 1024 * 8; -constexpr int TRAMPOLINE_CODE_SIZE_MMU = 1024 * 1024 * 32; - -// Stores information we need to batch-patch a MOV with a call to the slow read/write path after -// it faults. There will be 10s of thousands of these structs live, so be wary of making this too -// big. -struct TrampolineInfo final -{ - // The start of the store operation that failed -- we will patch a JMP here - u8* start; - - // The start + len = end of the store operation (points to the next instruction) - u32 len; - - // The PPC PC for the current load/store block - u32 pc; - - // Saved because we need these to make the ABI call in the trampoline - BitSet32 registersInUse; - - // The MOV operation - Gen::X64Reg nonAtomicSwapStoreSrc; - - // src/dest for load/store - s32 offset; - Gen::X64Reg op_reg; - Gen::OpArg op_arg; - - // Original SafeLoadXXX/SafeStoreXXX flags - u8 flags; - - // Memory access size (in bytes) - u8 accessSize : 4; - - // true if this is a read op vs a write - bool read : 1; - - // for read operations, true if needs sign-extension after load - bool signExtend : 1; - - // Set to true if we added the offset to the address and need to undo it - bool offsetAddedToAddress : 1; -}; - // Like XCodeBlock but has some utilities for memory access. class EmuCodeBlock : public Gen::X64CodeBlock { @@ -111,17 +28,8 @@ public: void MemoryExceptionCheck(); // Simple functions to switch between near and far code emitting - void SwitchToFarCode() - { - nearcode = GetWritableCodePtr(); - SetCodePtr(farcode.GetWritableCodePtr()); - } - - void SwitchToNearCode() - { - farcode.SetCodePtr(GetWritableCodePtr()); - SetCodePtr(nearcode); - } + void SwitchToFarCode(); + void SwitchToNearCode(); Gen::FixupBranch CheckIfSafeAddress(const Gen::OpArg& reg_value, Gen::X64Reg reg_addr, BitSet32 registers_in_use); @@ -133,10 +41,8 @@ public: void UnsafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset = 0, bool swap = true, Gen::MovInfo* info = nullptr); void UnsafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, - s32 offset = 0, bool swap = true, Gen::MovInfo* info = nullptr) - { - UnsafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, swap, info); - } + s32 offset = 0, bool swap = true, Gen::MovInfo* info = nullptr); + bool UnsafeLoadToReg(Gen::X64Reg reg_value, Gen::OpArg opAddress, int accessSize, s32 offset, bool signExtend, Gen::MovInfo* info = nullptr); void UnsafeWriteGatherPipe(int accessSize); @@ -169,20 +75,15 @@ public: void SafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset, BitSet32 registersInUse, int flags = 0); void SafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset, - BitSet32 registersInUse, int flags = 0) - { - SafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, registersInUse, flags); - } + BitSet32 registersInUse, int flags = 0); // applies to safe and unsafe WriteRegToReg - bool WriteClobbersRegValue(int accessSize, bool swap) - { - return swap && !cpu_info.bMOVBE && accessSize > 8; - } + bool WriteClobbersRegValue(int accessSize, bool swap); - void WriteToConstRamAddress(int accessSize, Gen::OpArg arg, u32 address, bool swap = true); // returns true if an exception could have been caused bool WriteToConstAddress(int accessSize, Gen::OpArg arg, u32 address, BitSet32 registersInUse); + void WriteToConstRamAddress(int accessSize, Gen::OpArg arg, u32 address, bool swap = true); + void JitGetAndClearCAOV(bool oe); void JitSetCA(); void JitSetCAIf(Gen::CCFlags conditionCode); diff --git a/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.cpp b/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.cpp new file mode 100644 index 0000000000..cd9d5a9462 --- /dev/null +++ b/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.cpp @@ -0,0 +1,22 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Core/PowerPC/Jit64Common/FarCodeCache.h" + +void FarCodeCache::Init(int size) +{ + AllocCodeSpace(size); + m_enabled = true; +} + +void FarCodeCache::Shutdown() +{ + FreeCodeSpace(); + m_enabled = false; +} + +bool FarCodeCache::Enabled() const +{ + return m_enabled; +} diff --git a/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.h b/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.h new file mode 100644 index 0000000000..2606de65fe --- /dev/null +++ b/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.h @@ -0,0 +1,26 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Common/x64Emitter.h" + +// a bit of a hack; the MMU results in a vast amount more code ending up in the far cache, +// mostly exception handling, so give it a whole bunch more space if the MMU is on. +constexpr int FARCODE_SIZE = 1024 * 1024 * 8; +constexpr int FARCODE_SIZE_MMU = 1024 * 1024 * 48; + +// A place to throw blocks of code we don't want polluting the cache, e.g. rarely taken +// exception branches. +class FarCodeCache : public Gen::X64CodeBlock +{ +public: + void Init(int size); + void Shutdown(); + + bool Enabled() const; + +private: + bool m_enabled = false; +}; diff --git a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp index e1ab7425ab..e9ec6cee8e 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp +++ b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp @@ -4,6 +4,7 @@ #include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h" #include "Common/Assert.h" +#include "Common/CPUDetect.h" #include "Common/CommonTypes.h" #include "Common/JitRegister.h" #include "Common/MathUtil.h" @@ -12,7 +13,7 @@ #include "Core/HW/GPFifo.h" #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/Jit64Common/Jit64Base.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/PowerPC.h" #define QUANTIZED_REGS_TO_SAVE \ diff --git a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.h b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.h index e4cdad983a..c098400f55 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.h +++ b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.h @@ -5,7 +5,7 @@ #pragma once #include "Common/CommonTypes.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" +#include "Core/PowerPC/Jit64Common/EmuCodeBlock.h" #include "Core/PowerPC/JitCommon/JitAsmCommon.h" enum EQuantizeType : u32; diff --git a/Source/Core/Core/PowerPC/Jit64Common/Jit64Base.h b/Source/Core/Core/PowerPC/Jit64Common/Jit64Base.h index 8aaec2c6d7..b6259dd430 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/Jit64Base.h +++ b/Source/Core/Core/PowerPC/Jit64Common/Jit64Base.h @@ -32,6 +32,8 @@ constexpr Gen::X64Reg RMEM = Gen::RBX; // to address as much as possible in a one-byte offset form. constexpr Gen::X64Reg RPPCSTATE = Gen::RBP; +constexpr int CODE_SIZE = 1024 * 1024 * 32; + class Jitx86Base : public JitBase, public QuantizedMemoryRoutines { protected: diff --git a/Source/Core/Core/PowerPC/Jit64Common/Jit64PowerPCState.h b/Source/Core/Core/PowerPC/Jit64Common/Jit64PowerPCState.h new file mode 100644 index 0000000000..48f2c039f5 --- /dev/null +++ b/Source/Core/Core/PowerPC/Jit64Common/Jit64PowerPCState.h @@ -0,0 +1,19 @@ +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included./ + +#pragma once + +#include "Common/CommonTypes.h" +#include "Core/PowerPC/PowerPC.h" + +// We offset by 0x80 because the range of one byte memory offsets is +// -0x80..0x7f. +#define PPCSTATE(x) \ + MDisp(RPPCSTATE, (int)((char*)&PowerPC::ppcState.x - (char*)&PowerPC::ppcState) - 0x80) +// In case you want to disable the ppcstate register: +// #define PPCSTATE(x) M(&PowerPC::ppcState.x) +#define PPCSTATE_LR PPCSTATE(spr[SPR_LR]) +#define PPCSTATE_CTR PPCSTATE(spr[SPR_CTR]) +#define PPCSTATE_SRR0 PPCSTATE(spr[SPR_SRR0]) +#define PPCSTATE_SRR1 PPCSTATE(spr[SPR_SRR1]) diff --git a/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.cpp b/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.cpp index 67a2e4a9e5..954aac6fc5 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.cpp @@ -12,7 +12,8 @@ #include "Common/MsgHandler.h" #include "Common/x64Emitter.h" #include "Core/PowerPC/Jit64Common/Jit64Base.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" +#include "Core/PowerPC/Jit64Common/TrampolineInfo.h" #include "Core/PowerPC/JitCommon/JitBase.h" #include "Core/PowerPC/PowerPC.h" diff --git a/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.h b/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.h index c9f2bcb41e..12ee83ec2d 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.h +++ b/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.h @@ -5,7 +5,14 @@ #pragma once #include "Common/CommonTypes.h" -#include "Core/PowerPC/Jit64Common/Jit64Util.h" +#include "Core/PowerPC/Jit64Common/EmuCodeBlock.h" + +struct TrampolineInfo; + +// a bit of a hack; the MMU results in more code ending up in the trampoline cache, +// because fastmem results in far more backpatches in MMU mode +constexpr int TRAMPOLINE_CODE_SIZE = 1024 * 1024 * 8; +constexpr int TRAMPOLINE_CODE_SIZE_MMU = 1024 * 1024 * 32; // We need at least this many bytes for backpatching. constexpr int BACKPATCH_SIZE = 5; diff --git a/Source/Core/Core/PowerPC/Jit64Common/TrampolineInfo.h b/Source/Core/Core/PowerPC/Jit64Common/TrampolineInfo.h new file mode 100644 index 0000000000..2ca6b2826a --- /dev/null +++ b/Source/Core/Core/PowerPC/Jit64Common/TrampolineInfo.h @@ -0,0 +1,50 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Common/BitSet.h" +#include "Common/CommonTypes.h" +#include "Common/x64Emitter.h" + +// Stores information we need to batch-patch a MOV with a call to the slow read/write path after +// it faults. There will be 10s of thousands of these structs live, so be wary of making this too +// big. +struct TrampolineInfo final +{ + // The start of the store operation that failed -- we will patch a JMP here + u8* start; + + // The start + len = end of the store operation (points to the next instruction) + u32 len; + + // The PPC PC for the current load/store block + u32 pc; + + // Saved because we need these to make the ABI call in the trampoline + BitSet32 registersInUse; + + // The MOV operation + Gen::X64Reg nonAtomicSwapStoreSrc; + + // src/dest for load/store + s32 offset; + Gen::X64Reg op_reg; + Gen::OpArg op_arg; + + // Original SafeLoadXXX/SafeStoreXXX flags + u8 flags; + + // Memory access size (in bytes) + u8 accessSize : 4; + + // true if this is a read op vs a write + bool read : 1; + + // for read operations, true if needs sign-extension after load + bool signExtend : 1; + + // Set to true if we added the offset to the address and need to undo it + bool offsetAddedToAddress : 1; +}; diff --git a/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp index 20b7919891..83eb202eb2 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp @@ -39,6 +39,7 @@ The register allocation is linear scan allocation. #include "Core/HW/CPU.h" #include "Core/HW/ProcessorInterface.h" #include "Core/PowerPC/Gekko.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/Jit64IL/JitIL.h" #include "Core/PowerPC/PowerPC.h" diff --git a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp index 62259cf579..0ec2375896 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp @@ -18,6 +18,7 @@ #include "Core/HLE/HLE.h" #include "Core/HW/CPU.h" #include "Core/PatchEngine.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/Jit64IL/JitIL.h" #include "Core/PowerPC/Jit64IL/JitIL_Tables.h" #include "Core/PowerPC/PowerPC.h" diff --git a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStorePaired.cpp index ec92f1ed08..5524f9db24 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStorePaired.cpp @@ -3,7 +3,9 @@ // Refer to the license.txt file included. #include "Core/PowerPC/JitILCommon/JitILBase.h" + #include "Common/CommonTypes.h" +#include "Core/PowerPC/PowerPC.h" void JitILBase::psq_st(UGeckoInstruction inst) {