commit
b47d44ab15
|
@ -219,22 +219,10 @@ set(SRCS
|
|||
PowerPC/JitCommon/JitAsmCommon.cpp
|
||||
PowerPC/JitCommon/JitBase.cpp
|
||||
PowerPC/JitCommon/JitCache.cpp
|
||||
PowerPC/JitILCommon/IR.cpp
|
||||
PowerPC/JitILCommon/JitILBase_Branch.cpp
|
||||
PowerPC/JitILCommon/JitILBase_LoadStore.cpp
|
||||
PowerPC/JitILCommon/JitILBase_SystemRegisters.cpp
|
||||
PowerPC/JitILCommon/JitILBase_LoadStoreFloating.cpp
|
||||
PowerPC/JitILCommon/JitILBase_LoadStorePaired.cpp
|
||||
PowerPC/JitILCommon/JitILBase_Paired.cpp
|
||||
PowerPC/JitILCommon/JitILBase_FloatingPoint.cpp
|
||||
PowerPC/JitILCommon/JitILBase_Integer.cpp
|
||||
)
|
||||
|
||||
if(_M_X86)
|
||||
set(SRCS ${SRCS}
|
||||
PowerPC/Jit64IL/IR_X86.cpp
|
||||
PowerPC/Jit64IL/JitIL.cpp
|
||||
PowerPC/Jit64IL/JitIL_Tables.cpp
|
||||
PowerPC/Jit64/FPURegCache.cpp
|
||||
PowerPC/Jit64/GPRRegCache.cpp
|
||||
PowerPC/Jit64/Jit64_Tables.cpp
|
||||
|
|
|
@ -581,8 +581,6 @@ void SConfig::LoadCoreSettings(IniFile& ini)
|
|||
core->Get("SlotB", (int*)&m_EXIDevice[1], ExpansionInterface::EXIDEVICE_NONE);
|
||||
core->Get("SerialPort1", (int*)&m_EXIDevice[2], ExpansionInterface::EXIDEVICE_NONE);
|
||||
core->Get("BBA_MAC", &m_bba_mac);
|
||||
core->Get("TimeProfiling", &bJITILTimeProfiling, false);
|
||||
core->Get("OutputIR", &bJITILOutputIR, false);
|
||||
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
|
||||
{
|
||||
core->Get(StringFromFormat("SIDevice%i", i), (u32*)&m_SIDevice[i],
|
||||
|
|
|
@ -74,9 +74,8 @@ struct SConfig : NonCopyable
|
|||
bool bAutomaticStart = false;
|
||||
bool bBootToPause = false;
|
||||
|
||||
int iCPUCore;
|
||||
int iCPUCore; // Uses the values of PowerPC::CPUCore
|
||||
|
||||
// JIT (shared between JIT and JITIL)
|
||||
bool bJITNoBlockCache = false;
|
||||
bool bJITNoBlockLinking = false;
|
||||
bool bJITOff = false;
|
||||
|
@ -91,8 +90,6 @@ struct SConfig : NonCopyable
|
|||
bool bJITPairedOff = false;
|
||||
bool bJITSystemRegistersOff = false;
|
||||
bool bJITBranchOff = false;
|
||||
bool bJITILTimeProfiling = false;
|
||||
bool bJITILOutputIR = false;
|
||||
|
||||
bool bFastmem;
|
||||
bool bFPRF = false;
|
||||
|
|
|
@ -249,18 +249,6 @@
|
|||
<ClCompile Include="PowerPC\Interpreter\Interpreter_SystemRegisters.cpp" />
|
||||
<ClCompile Include="PowerPC\Interpreter\Interpreter_Tables.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64Common\ConstantPool.cpp" />
|
||||
<ClCompile Include="PowerPC\JitILCommon\IR.cpp" />
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_Branch.cpp" />
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_FloatingPoint.cpp" />
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_Integer.cpp" />
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_LoadStore.cpp" />
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_LoadStoreFloating.cpp" />
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_LoadStorePaired.cpp" />
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_Paired.cpp" />
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_SystemRegisters.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64IL\IR_X86.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64IL\JitIL.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64IL\JitIL_Tables.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64\FPURegCache.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64\GPRRegCache.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64\Jit.cpp" />
|
||||
|
@ -496,14 +484,11 @@
|
|||
<ClInclude Include="PowerPC\Interpreter\Interpreter.h" />
|
||||
<ClInclude Include="PowerPC\Interpreter\Interpreter_FPUtils.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\ConstantPool.h" />
|
||||
<ClInclude Include="PowerPC\Jit64IL\JitIL.h" />
|
||||
<ClInclude Include="PowerPC\Jit64\FPURegCache.h" />
|
||||
<ClInclude Include="PowerPC\Jit64\GPRRegCache.h" />
|
||||
<ClInclude Include="PowerPC\Jit64\Jit.h" />
|
||||
<ClInclude Include="PowerPC\Jit64\JitAsm.h" />
|
||||
<ClInclude Include="PowerPC\Jit64\JitRegCache.h" />
|
||||
<ClInclude Include="PowerPC\JitILCommon\IR.h" />
|
||||
<ClInclude Include="PowerPC\JitILCommon\JitILBase.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\BlockCache.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\EmuCodeBlock.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\FarCodeCache.h" />
|
||||
|
|
|
@ -43,9 +43,6 @@
|
|||
<Filter Include="PowerPC\JitCommon">
|
||||
<UniqueIdentifier>{c88ec388-371f-4401-851c-a32dcdc0b88b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="PowerPC\JitIL">
|
||||
<UniqueIdentifier>{f26d3866-92d1-4623-9445-caf9a065ed74}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="DSPCore\Interpreter">
|
||||
<UniqueIdentifier>{6204f663-bbd0-4eb5-bc15-e3778d8b6091}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
@ -112,9 +109,6 @@
|
|||
<Filter Include="HW %28Flipper/Hollywood%29\Wii IPC">
|
||||
<UniqueIdentifier>{2b41ab45-ba8c-45dc-92cc-9107c1fa3e36}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="PowerPC\JitILCommon">
|
||||
<UniqueIdentifier>{827afa93-1a80-4835-93ae-b5516d95867f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="PowerPC\Jit64Common">
|
||||
<UniqueIdentifier>{81956f71-d9fe-454f-96a6-855195d611c4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
@ -631,15 +625,6 @@
|
|||
<ClCompile Include="PowerPC\JitCommon\JitCache.cpp">
|
||||
<Filter>PowerPC\JitCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64IL\IR_X86.cpp">
|
||||
<Filter>PowerPC\JitIL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64IL\JitIL.cpp">
|
||||
<Filter>PowerPC\JitIL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64IL\JitIL_Tables.cpp">
|
||||
<Filter>PowerPC\JitIL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64\FPURegCache.cpp">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClCompile>
|
||||
|
@ -676,33 +661,6 @@
|
|||
<ClCompile Include="PowerPC\Jit64\JitRegCache.cpp">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_Branch.cpp">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_FloatingPoint.cpp">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_Integer.cpp">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_LoadStore.cpp">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_LoadStoreFloating.cpp">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_LoadStorePaired.cpp">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_Paired.cpp">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\JitILCommon\JitILBase_SystemRegisters.cpp">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\JitILCommon\IR.cpp">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\GCKeyboardEmu.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\GCKeyboard</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1328,9 +1286,6 @@
|
|||
<ClInclude Include="PowerPC\JitCommon\JitCache.h">
|
||||
<Filter>PowerPC\JitCommon</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64IL\JitIL.h">
|
||||
<Filter>PowerPC\JitIL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64\FPURegCache.h">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClInclude>
|
||||
|
@ -1343,12 +1298,6 @@
|
|||
<ClInclude Include="PowerPC\Jit64\JitAsm.h">
|
||||
<Filter>PowerPC\Jit64</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\JitILCommon\JitILBase.h">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\JitILCommon\IR.h">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MachineContext.h" />
|
||||
<ClInclude Include="HW\GCKeyboardEmu.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\GCKeyboard</Filter>
|
||||
|
|
|
@ -81,7 +81,7 @@ struct DTMHeader
|
|||
bool bProgressive;
|
||||
bool bDSPHLE;
|
||||
bool bFastDiscSpeed;
|
||||
u8 CPUCore; // 0 = interpreter, 1 = JIT, 2 = JITIL
|
||||
u8 CPUCore; // Uses the values of PowerPC::CPUCore
|
||||
bool bEFBAccessEnable;
|
||||
bool bEFBCopyEnable;
|
||||
bool bSkipEFBCopyToRam;
|
||||
|
|
|
@ -19,7 +19,6 @@ namespace PPCAnalyst
|
|||
class CodeBuffer;
|
||||
}
|
||||
|
||||
// The following register assignments are common to Jit64 and Jit64IL:
|
||||
// RSCRATCH and RSCRATCH2 are always scratch registers and can be used without
|
||||
// limitation.
|
||||
constexpr Gen::X64Reg RSCRATCH = Gen::RAX;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,688 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/Jit64IL/JitIL.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <ctime> // For profiling
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Intrinsics.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/x64ABI.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HW/CPU.h"
|
||||
#include "Core/PatchEngine.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/PowerPC/Profiler.h"
|
||||
|
||||
using namespace Gen;
|
||||
using namespace PowerPC;
|
||||
|
||||
// Dolphin's PowerPC->x86 JIT dynamic recompiler
|
||||
// (Nearly) all code by ector (hrydgard)
|
||||
// Features:
|
||||
// * x86 & x64 support, lots of shared code.
|
||||
// * Basic block linking
|
||||
// * Fast dispatcher
|
||||
|
||||
// Unfeatures:
|
||||
// * Does not recompile all instructions - sometimes falls back to inserting a CALL to the
|
||||
// corresponding Interpreter function.
|
||||
|
||||
// Various notes below
|
||||
|
||||
// Register allocation
|
||||
// RAX - Generic quicktemp register
|
||||
// RBX - point to base of memory map
|
||||
// RSI RDI R12 R13 R14 R15 - free for allocation
|
||||
// RCX RDX R8 R9 R10 R11 - allocate in emergencies. These need to be flushed before functions are
|
||||
// called.
|
||||
// RSP - stack pointer, do not generally use, very dangerous
|
||||
// RBP - ?
|
||||
|
||||
// IMPORTANT:
|
||||
// Make sure that all generated code and all emulator state sits under the 2GB boundary so that
|
||||
// RIP addressing can be used easily. Windows will always allocate static code under the 2GB
|
||||
// boundary.
|
||||
// Also make sure to use VirtualAlloc and specify EXECUTE permission.
|
||||
|
||||
// Open questions
|
||||
// * Should there be any statically allocated registers? r3, r4, r5, r8, r0 come to mind.. maybe sp
|
||||
// * Does it make sense to finish off the remaining non-jitted instructions? Seems we are hitting
|
||||
// diminishing returns.
|
||||
|
||||
// Other considerations
|
||||
//
|
||||
// Many instructions have shorter forms for EAX. However, I believe their performance boost
|
||||
// will be as small to be negligible, so I haven't dirtied up the code with that. AMD recommends it
|
||||
// in their
|
||||
// optimization manuals, though.
|
||||
//
|
||||
// We support block linking. Reserve space at the exits of every block for a full 5-byte jmp. Save
|
||||
// 16-bit offsets
|
||||
// from the starts of each block, marking the exits so that they can be nicely patched at any time.
|
||||
//
|
||||
// Blocks do NOT use call/ret, they only jmp to each other and to the dispatcher when necessary.
|
||||
//
|
||||
// All blocks that can be precompiled will be precompiled. Code will be memory protected - any write
|
||||
// will mark
|
||||
// the region as non-compilable, and all links to the page will be torn out and replaced with
|
||||
// dispatcher jmps.
|
||||
//
|
||||
// Alternatively, icbi instruction SHOULD mark where we can't compile
|
||||
//
|
||||
// Seldom-happening events is handled by adding a decrement of a counter to all blr instructions
|
||||
// (which are
|
||||
// expensive anyway since we need to return to dispatcher, except when they can be predicted).
|
||||
|
||||
// TODO: SERIOUS synchronization problem with the video backend setting tokens and breakpoints in
|
||||
// dual core mode!!!
|
||||
// Somewhat fixed by disabling idle skipping when certain interrupts are enabled
|
||||
// This is no permanent reliable fix
|
||||
// TODO: Zeldas go whacko when you hang the gfx thread
|
||||
|
||||
// Idea - Accurate exception handling
|
||||
// Compute register state at a certain instruction by running the JIT in "dry mode", and stopping at
|
||||
// the right place.
|
||||
// Not likely to be done :P
|
||||
|
||||
// Optimization Ideas -
|
||||
/*
|
||||
* Assume SP is in main RAM (in Wii mode too?) - partly done
|
||||
* Assume all floating point loads and double precision loads+stores are to/from main ram
|
||||
(single precision can be used in write gather pipe, specialized fast check added)
|
||||
* AMD only - use movaps instead of movapd when loading ps from memory?
|
||||
* HLE functions like floorf, sin, memcpy, etc - they can be much faster
|
||||
* ABI optimizations - drop F0-F13 on blr, for example. Watch out for context switching.
|
||||
CR2-CR4 are non-volatile, rest of CR is volatile -> dropped on blr.
|
||||
R5-R12 are volatile -> dropped on blr.
|
||||
* classic inlining across calls.
|
||||
|
||||
Low hanging fruit:
|
||||
stfd -- guaranteed in memory
|
||||
cmpl
|
||||
mulli
|
||||
stfs
|
||||
stwu
|
||||
lb/stzx
|
||||
|
||||
bcx - optimize!
|
||||
bcctr
|
||||
stfs
|
||||
psq_st
|
||||
addx
|
||||
orx
|
||||
rlwimix
|
||||
fcmpo
|
||||
DSP_UpdateARAMDMA
|
||||
lfd
|
||||
stwu
|
||||
cntlzwx
|
||||
bcctrx
|
||||
WriteBigEData
|
||||
|
||||
TODO
|
||||
lha
|
||||
srawx
|
||||
addic_rc
|
||||
addex
|
||||
subfcx
|
||||
subfex
|
||||
|
||||
fmaddx
|
||||
fmulx
|
||||
faddx
|
||||
fnegx
|
||||
frspx
|
||||
frsqrtex
|
||||
ps_sum0
|
||||
ps_muls0
|
||||
ps_adds1
|
||||
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__clang__)
|
||||
#if !__has_builtin(__builtin_ia32_rdtsc)
|
||||
static inline uint64_t __rdtsc()
|
||||
{
|
||||
uint32_t lo, hi;
|
||||
#ifdef _LP64
|
||||
__asm__ __volatile__("xorl %%eax,%%eax \n cpuid" ::: "%rax", "%rbx", "%rcx", "%rdx");
|
||||
__asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return (uint64_t)hi << 32 | lo;
|
||||
#else
|
||||
__asm__ __volatile__("xor %%eax,%%eax;"
|
||||
"push %%ebx;"
|
||||
"cpuid;"
|
||||
"pop %%ebx;" ::
|
||||
: "%eax", "%ecx", "%edx");
|
||||
__asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
#endif
|
||||
return (uint64_t)hi << 32 | lo;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace JitILProfiler
|
||||
{
|
||||
struct Block
|
||||
{
|
||||
u32 index;
|
||||
u64 codeHash;
|
||||
u64 totalElapsed;
|
||||
u64 numberOfCalls;
|
||||
|
||||
Block() : index(0), codeHash(0), totalElapsed(0), numberOfCalls(0) {}
|
||||
};
|
||||
|
||||
static std::vector<Block> blocks;
|
||||
static u32 blockIndex;
|
||||
static u64 beginTime;
|
||||
static Block& Add(u64 codeHash)
|
||||
{
|
||||
const u32 _blockIndex = (u32)blocks.size();
|
||||
blocks.emplace_back();
|
||||
Block& block = blocks.back();
|
||||
block.index = _blockIndex;
|
||||
block.codeHash = codeHash;
|
||||
return block;
|
||||
}
|
||||
|
||||
// These functions need to be static because they are called with
|
||||
// ABI_CallFunction().
|
||||
static void Begin(u32 index)
|
||||
{
|
||||
blockIndex = index;
|
||||
beginTime = __rdtsc();
|
||||
}
|
||||
|
||||
static void End()
|
||||
{
|
||||
const u64 endTime = __rdtsc();
|
||||
const u64 duration = endTime - beginTime;
|
||||
Block& block = blocks[blockIndex];
|
||||
block.totalElapsed += duration;
|
||||
++block.numberOfCalls;
|
||||
}
|
||||
|
||||
struct JitILProfilerFinalizer
|
||||
{
|
||||
virtual ~JitILProfilerFinalizer()
|
||||
{
|
||||
std::string filename = StringFromFormat("JitIL_profiling_%d.csv", (int)time(nullptr));
|
||||
File::IOFile file(filename, "w");
|
||||
setvbuf(file.GetHandle(), nullptr, _IOFBF, 1024 * 1024);
|
||||
fprintf(file.GetHandle(), "code hash,total elapsed,number of calls,elapsed per call\n");
|
||||
for (auto& block : blocks)
|
||||
{
|
||||
const u64 codeHash = block.codeHash;
|
||||
const u64 totalElapsed = block.totalElapsed;
|
||||
const u64 numberOfCalls = block.numberOfCalls;
|
||||
const double elapsedPerCall = totalElapsed / (double)numberOfCalls;
|
||||
fprintf(file.GetHandle(), "%016" PRIx64 ",%" PRId64 ",%" PRId64 ",%f\n", codeHash,
|
||||
totalElapsed, numberOfCalls, elapsedPerCall);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static std::unique_ptr<JitILProfilerFinalizer> finalizer;
|
||||
static void Init()
|
||||
{
|
||||
finalizer = std::make_unique<JitILProfilerFinalizer>();
|
||||
}
|
||||
|
||||
static void Shutdown()
|
||||
{
|
||||
finalizer.reset();
|
||||
}
|
||||
};
|
||||
|
||||
void JitIL::Init()
|
||||
{
|
||||
InitializeInstructionTables();
|
||||
EnableBlockLink();
|
||||
|
||||
jo.optimizeGatherPipe = true;
|
||||
jo.accurateSinglePrecision = false;
|
||||
UpdateMemoryOptions();
|
||||
|
||||
const size_t routines_size = asm_routines.CODE_SIZE;
|
||||
const size_t trampolines_size = jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE;
|
||||
const size_t farcode_size = jo.memcheck ? FARCODE_SIZE_MMU : FARCODE_SIZE;
|
||||
const size_t constpool_size = m_const_pool.CONST_POOL_SIZE;
|
||||
AllocCodeSpace(CODE_SIZE + routines_size + trampolines_size + farcode_size + constpool_size);
|
||||
AddChildCodeSpace(&asm_routines, routines_size);
|
||||
AddChildCodeSpace(&trampolines, trampolines_size);
|
||||
AddChildCodeSpace(&m_far_code, farcode_size);
|
||||
m_const_pool.Init(AllocChildCodeSpace(constpool_size), constpool_size);
|
||||
|
||||
blocks.Init();
|
||||
asm_routines.Init(nullptr);
|
||||
m_far_code.Init();
|
||||
Clear();
|
||||
|
||||
code_block.m_stats = &js.st;
|
||||
code_block.m_gpa = &js.gpa;
|
||||
code_block.m_fpa = &js.fpa;
|
||||
|
||||
if (SConfig::GetInstance().bJITILTimeProfiling)
|
||||
{
|
||||
JitILProfiler::Init();
|
||||
}
|
||||
}
|
||||
|
||||
void JitIL::ClearCache()
|
||||
{
|
||||
blocks.Clear();
|
||||
trampolines.ClearCodeSpace();
|
||||
m_far_code.ClearCodeSpace();
|
||||
ClearCodeSpace();
|
||||
Clear();
|
||||
}
|
||||
|
||||
void JitIL::Shutdown()
|
||||
{
|
||||
if (SConfig::GetInstance().bJITILTimeProfiling)
|
||||
{
|
||||
JitILProfiler::Shutdown();
|
||||
}
|
||||
|
||||
FreeCodeSpace();
|
||||
|
||||
blocks.Shutdown();
|
||||
m_far_code.Shutdown();
|
||||
}
|
||||
|
||||
void JitIL::FallBackToInterpreter(UGeckoInstruction _inst)
|
||||
{
|
||||
ibuild.EmitFallBackToInterpreter(ibuild.EmitIntConst(_inst.hex),
|
||||
ibuild.EmitIntConst(js.compilerPC));
|
||||
}
|
||||
|
||||
void JitIL::HLEFunction(UGeckoInstruction _inst)
|
||||
{
|
||||
ABI_CallFunctionCC(HLE::Execute, js.compilerPC, _inst.hex);
|
||||
MOV(32, R(RSCRATCH), PPCSTATE(npc));
|
||||
WriteExitDestInOpArg(R(RSCRATCH));
|
||||
}
|
||||
|
||||
void JitIL::DoNothing(UGeckoInstruction _inst)
|
||||
{
|
||||
// Yup, just don't do anything.
|
||||
}
|
||||
|
||||
static const bool ImHereDebug = false;
|
||||
static const bool ImHereLog = false;
|
||||
static std::map<u32, int> been_here;
|
||||
|
||||
static void ImHere()
|
||||
{
|
||||
static File::IOFile f;
|
||||
if (ImHereLog)
|
||||
{
|
||||
if (!f)
|
||||
{
|
||||
f.Open("log64.txt", "w");
|
||||
}
|
||||
fprintf(f.GetHandle(), "%08x r0: %08x r5: %08x r6: %08x\n", PC, PowerPC::ppcState.gpr[0],
|
||||
PowerPC::ppcState.gpr[5], PowerPC::ppcState.gpr[6]);
|
||||
f.Flush();
|
||||
}
|
||||
|
||||
if (been_here.find(PC) != been_here.end())
|
||||
{
|
||||
been_here.find(PC)->second++;
|
||||
if ((been_here.find(PC)->second) & 1023)
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR);
|
||||
been_here[PC] = 1;
|
||||
}
|
||||
|
||||
void JitIL::Cleanup()
|
||||
{
|
||||
// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time.
|
||||
if (MMCR0.Hex || MMCR1.Hex)
|
||||
ABI_CallFunctionCCC(PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst,
|
||||
js.numFloatingPointInst);
|
||||
}
|
||||
|
||||
void JitIL::WriteExit(u32 destination)
|
||||
{
|
||||
Cleanup();
|
||||
if (SConfig::GetInstance().bJITILTimeProfiling)
|
||||
{
|
||||
ABI_CallFunction(JitILProfiler::End);
|
||||
}
|
||||
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
|
||||
|
||||
// If nobody has taken care of this yet (this can be removed when all branches are done)
|
||||
JitBlock* b = js.curBlock;
|
||||
JitBlock::LinkData linkData;
|
||||
linkData.exitAddress = destination;
|
||||
linkData.exitPtrs = GetWritableCodePtr();
|
||||
linkData.linkStatus = false;
|
||||
|
||||
MOV(32, PPCSTATE(pc), Imm32(destination));
|
||||
JMP(asm_routines.dispatcher, true);
|
||||
|
||||
b->linkData.push_back(linkData);
|
||||
}
|
||||
|
||||
void JitIL::WriteExitDestInOpArg(const OpArg& arg)
|
||||
{
|
||||
MOV(32, PPCSTATE(pc), arg);
|
||||
Cleanup();
|
||||
if (SConfig::GetInstance().bJITILTimeProfiling)
|
||||
{
|
||||
ABI_CallFunction(JitILProfiler::End);
|
||||
}
|
||||
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
|
||||
JMP(asm_routines.dispatcher, true);
|
||||
}
|
||||
|
||||
void JitIL::WriteRfiExitDestInOpArg(const OpArg& arg)
|
||||
{
|
||||
MOV(32, PPCSTATE(pc), arg);
|
||||
MOV(32, PPCSTATE(npc), arg);
|
||||
Cleanup();
|
||||
if (SConfig::GetInstance().bJITILTimeProfiling)
|
||||
{
|
||||
ABI_CallFunction(JitILProfiler::End);
|
||||
}
|
||||
ABI_CallFunction(PowerPC::CheckExceptions);
|
||||
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
|
||||
JMP(asm_routines.dispatcher, true);
|
||||
}
|
||||
|
||||
void JitIL::WriteExceptionExit()
|
||||
{
|
||||
Cleanup();
|
||||
if (SConfig::GetInstance().bJITILTimeProfiling)
|
||||
{
|
||||
ABI_CallFunction(JitILProfiler::End);
|
||||
}
|
||||
MOV(32, R(EAX), PPCSTATE(pc));
|
||||
MOV(32, PPCSTATE(npc), R(EAX));
|
||||
ABI_CallFunction(PowerPC::CheckExceptions);
|
||||
SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount));
|
||||
JMP(asm_routines.dispatcher, true);
|
||||
}
|
||||
|
||||
void JitIL::Run()
|
||||
{
|
||||
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
|
||||
pExecAddr();
|
||||
// Will return when PowerPC::state changes
|
||||
}
|
||||
|
||||
void JitIL::SingleStep()
|
||||
{
|
||||
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
|
||||
pExecAddr();
|
||||
}
|
||||
|
||||
void JitIL::Trace()
|
||||
{
|
||||
std::string regs;
|
||||
std::string fregs;
|
||||
|
||||
#ifdef JIT_LOG_GPR
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
regs += StringFromFormat("r%02d: %08x ", i, PowerPC::ppcState.gpr[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JIT_LOG_FPR
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
fregs += StringFromFormat("f%02d: %016x ", i, riPS0(i));
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUG_LOG(DYNA_REC, "JITIL PC: %08x SRR0: %08x SRR1: %08x CRval: "
|
||||
"%016lx%016lx%016lx%016lx%016lx%016lx%016lx%016lx FPSCR: %08x MSR: %08x LR: "
|
||||
"%08x %s %s",
|
||||
PC, SRR0, SRR1, (unsigned long)PowerPC::ppcState.cr_val[0],
|
||||
(unsigned long)PowerPC::ppcState.cr_val[1], (unsigned long)PowerPC::ppcState.cr_val[2],
|
||||
(unsigned long)PowerPC::ppcState.cr_val[3], (unsigned long)PowerPC::ppcState.cr_val[4],
|
||||
(unsigned long)PowerPC::ppcState.cr_val[5], (unsigned long)PowerPC::ppcState.cr_val[6],
|
||||
(unsigned long)PowerPC::ppcState.cr_val[7], PowerPC::ppcState.fpscr,
|
||||
PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str());
|
||||
}
|
||||
|
||||
void JitIL::Jit(u32 em_address)
|
||||
{
|
||||
if (IsAlmostFull() || m_far_code.IsAlmostFull() || trampolines.IsAlmostFull() ||
|
||||
SConfig::GetInstance().bJITNoBlockCache)
|
||||
{
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
int blockSize = code_buffer.GetSize();
|
||||
|
||||
if (SConfig::GetInstance().bEnableDebugging)
|
||||
{
|
||||
// We can link blocks as long as we are not single stepping and there are no breakpoints here
|
||||
EnableBlockLink();
|
||||
|
||||
// Comment out the following to disable breakpoints (speed-up)
|
||||
if (!Profiler::g_ProfileBlocks)
|
||||
{
|
||||
if (CPU::IsStepping())
|
||||
{
|
||||
blockSize = 1;
|
||||
|
||||
// Do not link this block to other blocks While single stepping
|
||||
jo.enableBlocklink = false;
|
||||
}
|
||||
Trace();
|
||||
}
|
||||
}
|
||||
|
||||
// Analyze the block, collect all instructions it is made of (including inlining,
|
||||
// if that is enabled), reorder instructions for optimal performance, and join joinable
|
||||
// instructions.
|
||||
u32 nextPC = analyzer.Analyze(em_address, &code_block, &code_buffer, blockSize);
|
||||
|
||||
if (code_block.m_memory_exception)
|
||||
{
|
||||
// Address of instruction could not be translated
|
||||
NPC = nextPC;
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
||||
PowerPC::CheckExceptions();
|
||||
WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC);
|
||||
return;
|
||||
}
|
||||
|
||||
JitBlock* b = blocks.AllocateBlock(em_address);
|
||||
DoJit(em_address, &code_buffer, b, nextPC);
|
||||
blocks.FinalizeBlock(*b, jo.enableBlocklink, code_block.m_physical_addresses);
|
||||
}
|
||||
|
||||
const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC)
|
||||
{
|
||||
js.isLastInstruction = false;
|
||||
js.blockStart = em_address;
|
||||
js.fifoBytesSinceCheck = 0;
|
||||
js.curBlock = b;
|
||||
js.numLoadStoreInst = 0;
|
||||
js.numFloatingPointInst = 0;
|
||||
|
||||
PPCAnalyst::CodeOp* ops = code_buf->codebuffer;
|
||||
|
||||
const u8* start =
|
||||
AlignCode4(); // TODO: Test if this or AlignCode16 make a difference from GetCodePtr
|
||||
b->checkedEntry = start;
|
||||
b->runCount = 0;
|
||||
|
||||
// Downcount flag check. The last block decremented downcounter, and the flag should still be
|
||||
// available.
|
||||
FixupBranch skip = J_CC(CC_NBE);
|
||||
MOV(32, PPCSTATE(pc), Imm32(js.blockStart));
|
||||
JMP(asm_routines.doTiming, true); // downcount hit zero - go doTiming.
|
||||
SetJumpTarget(skip);
|
||||
|
||||
const u8* normalEntry = GetCodePtr();
|
||||
b->normalEntry = normalEntry;
|
||||
|
||||
// Used to get a trace of the last few blocks before a crash, sometimes VERY useful.
|
||||
if (ImHereDebug)
|
||||
ABI_CallFunction(ImHere);
|
||||
|
||||
if (js.fpa.any)
|
||||
{
|
||||
// This block uses FPU - needs to add FP exception bailout
|
||||
TEST(32, PPCSTATE(msr), Imm32(1 << 13)); // Test FP enabled bit
|
||||
FixupBranch b1 = J_CC(CC_NZ);
|
||||
|
||||
// If a FPU exception occurs, the exception handler will read
|
||||
// from PC. Update PC with the latest value in case that happens.
|
||||
MOV(32, PPCSTATE(pc), Imm32(js.blockStart));
|
||||
OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
|
||||
WriteExceptionExit();
|
||||
|
||||
SetJumpTarget(b1);
|
||||
}
|
||||
|
||||
js.rewriteStart = (u8*)GetCodePtr();
|
||||
|
||||
u64 codeHash = -1;
|
||||
if (SConfig::GetInstance().bJITILTimeProfiling || SConfig::GetInstance().bJITILOutputIR)
|
||||
{
|
||||
// For profiling and IR Writer
|
||||
for (u32 i = 0; i < code_block.m_num_instructions; i++)
|
||||
{
|
||||
const u64 inst = ops[i].inst.hex;
|
||||
// Ported from boost::hash
|
||||
codeHash ^= inst + (codeHash << 6) + (codeHash >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (SConfig::GetInstance().bJITILTimeProfiling)
|
||||
{
|
||||
JitILProfiler::Block& block = JitILProfiler::Add(codeHash);
|
||||
ABI_CallFunctionC(JitILProfiler::Begin, block.index);
|
||||
}
|
||||
|
||||
// Start up IR builder (structure that collects the
|
||||
// instruction processed by the JIT routines)
|
||||
ibuild.Reset();
|
||||
|
||||
js.downcountAmount = 0;
|
||||
|
||||
// Translate instructions
|
||||
for (u32 i = 0; i < code_block.m_num_instructions; i++)
|
||||
{
|
||||
js.compilerPC = ops[i].address;
|
||||
js.op = &ops[i];
|
||||
js.instructionNumber = i;
|
||||
const GekkoOPInfo* opinfo = GetOpInfo(ops[i].inst);
|
||||
js.downcountAmount += opinfo->numCycles;
|
||||
|
||||
if (!SConfig::GetInstance().bEnableDebugging)
|
||||
js.downcountAmount += PatchEngine::GetSpeedhackCycles(js.compilerPC);
|
||||
|
||||
if (i == (code_block.m_num_instructions - 1))
|
||||
js.isLastInstruction = true;
|
||||
|
||||
u32 function = HLE::GetFirstFunctionIndex(ops[i].address);
|
||||
if (function != 0)
|
||||
{
|
||||
int type = HLE::GetFunctionTypeByIndex(function);
|
||||
if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE)
|
||||
{
|
||||
int flags = HLE::GetFunctionFlagsByIndex(function);
|
||||
if (HLE::IsEnabled(flags))
|
||||
{
|
||||
HLEFunction(function);
|
||||
if (type == HLE::HLE_HOOK_REPLACE)
|
||||
{
|
||||
MOV(32, R(EAX), PPCSTATE(npc));
|
||||
js.downcountAmount += js.st.numCycles;
|
||||
WriteExitDestInOpArg(R(EAX));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ops[i].skip)
|
||||
{
|
||||
if (jo.memcheck && (opinfo->flags & FL_USE_FPU))
|
||||
{
|
||||
ibuild.EmitFPExceptionCheck(ibuild.EmitIntConst(ops[i].address));
|
||||
}
|
||||
|
||||
if (js.fifoWriteAddresses.find(js.compilerPC) != js.fifoWriteAddresses.end())
|
||||
{
|
||||
ibuild.EmitExtExceptionCheck(ibuild.EmitIntConst(ops[i].address));
|
||||
}
|
||||
|
||||
if (SConfig::GetInstance().bEnableDebugging &&
|
||||
breakpoints.IsAddressBreakPoint(ops[i].address) && !CPU::IsStepping())
|
||||
{
|
||||
// Turn off block linking if there are breakpoints so that the Step Over command does not
|
||||
// link this block.
|
||||
jo.enableBlocklink = false;
|
||||
|
||||
ibuild.EmitBreakPointCheck(ibuild.EmitIntConst(ops[i].address));
|
||||
}
|
||||
|
||||
CompileInstruction(ops[i]);
|
||||
|
||||
if (jo.memcheck && (opinfo->flags & FL_LOADSTORE))
|
||||
{
|
||||
ibuild.EmitDSIExceptionCheck(ibuild.EmitIntConst(ops[i].address));
|
||||
}
|
||||
|
||||
if (opinfo->flags & FL_LOADSTORE)
|
||||
++js.numLoadStoreInst;
|
||||
|
||||
if (opinfo->flags & FL_USE_FPU)
|
||||
++js.numFloatingPointInst;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform actual code generation
|
||||
WriteCode(nextPC);
|
||||
|
||||
b->codeSize = (u32)(GetCodePtr() - start);
|
||||
b->originalSize = code_block.m_num_instructions;
|
||||
|
||||
#ifdef JIT_LOG_X86
|
||||
LogGeneratedX86(code_block.m_num_instructions, code_buf, normalEntry, b);
|
||||
#endif
|
||||
|
||||
if (SConfig::GetInstance().bJITILOutputIR)
|
||||
{
|
||||
ibuild.WriteToFile(codeHash);
|
||||
}
|
||||
|
||||
return normalEntry;
|
||||
}
|
||||
|
||||
void JitIL::EnableBlockLink()
|
||||
{
|
||||
jo.enableBlocklink = true;
|
||||
if (SConfig::GetInstance().bJITNoBlockLinking)
|
||||
jo.enableBlocklink = false;
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// ========================
|
||||
// See comments in Jit.cpp.
|
||||
// ========================
|
||||
|
||||
// Mystery: Capcom vs SNK 800aa278
|
||||
|
||||
// CR flags approach:
|
||||
// * Store that "N+Z flag contains CR0" or "S+Z flag contains CR3".
|
||||
// * All flag altering instructions flush this
|
||||
// * A flush simply does a conditional write to the appropriate CRx.
|
||||
// * If flag available, branch code can become absolutely trivial.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/x64ABI.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/Jit64/JitAsm.h"
|
||||
#include "Core/PowerPC/JitCommon/JitCache.h"
|
||||
#include "Core/PowerPC/JitILCommon/JitILBase.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
|
||||
class JitIL : public JitILBase
|
||||
{
|
||||
public:
|
||||
Jit64AsmRoutineManager asm_routines;
|
||||
|
||||
JitIL() {}
|
||||
~JitIL() {}
|
||||
// Initialization, etc
|
||||
|
||||
void Init() override;
|
||||
void Shutdown() override;
|
||||
|
||||
void EnableBlockLink();
|
||||
|
||||
// Jit!
|
||||
|
||||
void Jit(u32 em_address) override;
|
||||
const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC);
|
||||
|
||||
void Trace();
|
||||
|
||||
JitBlockCache* GetBlockCache() override { return &blocks; }
|
||||
void ClearCache() override;
|
||||
|
||||
const CommonAsmRoutines* GetAsmRoutines() override { return &asm_routines; }
|
||||
const char* GetName() override { return "JIT64IL"; }
|
||||
// Run!
|
||||
void Run() override;
|
||||
void SingleStep() override;
|
||||
|
||||
// Utilities for use by opcodes
|
||||
|
||||
void WriteExit(u32 destination);
|
||||
void WriteExitDestInOpArg(const Gen::OpArg& arg);
|
||||
void WriteExceptionExit();
|
||||
void WriteRfiExitDestInOpArg(const Gen::OpArg& arg);
|
||||
void Cleanup();
|
||||
|
||||
void WriteCode(u32 exitAddress);
|
||||
|
||||
// OPCODES
|
||||
using Instruction = void (JitIL::*)(UGeckoInstruction instCode);
|
||||
void FallBackToInterpreter(UGeckoInstruction _inst) override;
|
||||
void DoNothing(UGeckoInstruction _inst) override;
|
||||
void HLEFunction(UGeckoInstruction _inst) override;
|
||||
|
||||
void DynaRunTable4(UGeckoInstruction _inst) override;
|
||||
void DynaRunTable19(UGeckoInstruction _inst) override;
|
||||
void DynaRunTable31(UGeckoInstruction _inst) override;
|
||||
void DynaRunTable59(UGeckoInstruction _inst) override;
|
||||
void DynaRunTable63(UGeckoInstruction _inst) override;
|
||||
|
||||
private:
|
||||
static void InitializeInstructionTables();
|
||||
void CompileInstruction(PPCAnalyst::CodeOp& op);
|
||||
};
|
|
@ -1,493 +0,0 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/Jit64IL/JitIL.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/PPCTables.h"
|
||||
|
||||
static JitIL::Instruction dynaOpTable[64];
|
||||
static JitIL::Instruction dynaOpTable4[1024];
|
||||
static JitIL::Instruction dynaOpTable19[1024];
|
||||
static JitIL::Instruction dynaOpTable31[1024];
|
||||
static JitIL::Instruction dynaOpTable59[32];
|
||||
static JitIL::Instruction dynaOpTable63[1024];
|
||||
|
||||
void JitIL::DynaRunTable4(UGeckoInstruction _inst)
|
||||
{
|
||||
(this->*dynaOpTable4[_inst.SUBOP10])(_inst);
|
||||
}
|
||||
void JitIL::DynaRunTable19(UGeckoInstruction _inst)
|
||||
{
|
||||
(this->*dynaOpTable19[_inst.SUBOP10])(_inst);
|
||||
}
|
||||
void JitIL::DynaRunTable31(UGeckoInstruction _inst)
|
||||
{
|
||||
(this->*dynaOpTable31[_inst.SUBOP10])(_inst);
|
||||
}
|
||||
void JitIL::DynaRunTable59(UGeckoInstruction _inst)
|
||||
{
|
||||
(this->*dynaOpTable59[_inst.SUBOP5])(_inst);
|
||||
}
|
||||
void JitIL::DynaRunTable63(UGeckoInstruction _inst)
|
||||
{
|
||||
(this->*dynaOpTable63[_inst.SUBOP10])(_inst);
|
||||
}
|
||||
|
||||
struct GekkoOPTemplate
|
||||
{
|
||||
int opcode;
|
||||
JitIL::Instruction Inst;
|
||||
};
|
||||
|
||||
const GekkoOPTemplate primarytable[] = {
|
||||
{4, &JitIL::DynaRunTable4}, //"RunTable4", OPTYPE_SUBTABLE | (4<<24), 0}},
|
||||
{19, &JitIL::DynaRunTable19}, //"RunTable19", OPTYPE_SUBTABLE | (19<<24), 0}},
|
||||
{31, &JitIL::DynaRunTable31}, //"RunTable31", OPTYPE_SUBTABLE | (31<<24), 0}},
|
||||
{59, &JitIL::DynaRunTable59}, //"RunTable59", OPTYPE_SUBTABLE | (59<<24), 0}},
|
||||
{63, &JitIL::DynaRunTable63}, //"RunTable63", OPTYPE_SUBTABLE | (63<<24), 0}},
|
||||
|
||||
{16, &JitIL::bcx}, //"bcx", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||
{18, &JitIL::bx}, //"bx", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||
|
||||
{3, &JitIL::FallBackToInterpreter}, //"twi", OPTYPE_SYSTEM, 0}},
|
||||
{17, &JitIL::sc}, //"sc", OPTYPE_SYSTEM, FL_ENDBLOCK, 1}},
|
||||
|
||||
{7, &JitIL::mulli}, //"mulli", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_RC_BIT, 2}},
|
||||
{8, &JitIL::subfic}, //"subfic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}},
|
||||
{10, &JitIL::cmpXX}, //"cmpli", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}},
|
||||
{11, &JitIL::cmpXX}, //"cmpi", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}},
|
||||
{12, &JitIL::reg_imm}, //"addic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}},
|
||||
{13, &JitIL::reg_imm}, //"addic_rc", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CR0}},
|
||||
{14, &JitIL::reg_imm}, //"addi", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}},
|
||||
{15, &JitIL::reg_imm}, //"addis", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}},
|
||||
|
||||
{20,
|
||||
&JitIL::rlwimix}, //"rlwimix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_A | FL_IN_S | FL_RC_BIT}},
|
||||
{21, &JitIL::rlwinmx}, //"rlwinmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}},
|
||||
{23, &JitIL::rlwnmx}, //"rlwnmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_IN_B | FL_RC_BIT}},
|
||||
|
||||
{24, &JitIL::reg_imm}, //"ori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||
{25, &JitIL::reg_imm}, //"oris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||
{26, &JitIL::reg_imm}, //"xori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||
{27, &JitIL::reg_imm}, //"xoris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}},
|
||||
{28, &JitIL::reg_imm}, //"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}},
|
||||
{29, &JitIL::reg_imm}, //"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}},
|
||||
|
||||
{32, &JitIL::lXz}, //"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
|
||||
{33, &JitIL::lXz}, //"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
|
||||
{34, &JitIL::lXz}, //"lbz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
|
||||
{35, &JitIL::lbzu}, //"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
|
||||
{40, &JitIL::lXz}, //"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
|
||||
{41, &JitIL::lXz}, //"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
|
||||
{42, &JitIL::lha}, //"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
|
||||
{43, &JitIL::lhau}, //"lhau", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
|
||||
|
||||
{44, &JitIL::stX}, //"sth", OPTYPE_STORE, FL_IN_A | FL_IN_S}},
|
||||
{45, &JitIL::stX}, //"sthu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}},
|
||||
{36, &JitIL::stX}, //"stw", OPTYPE_STORE, FL_IN_A | FL_IN_S}},
|
||||
{37, &JitIL::stX}, //"stwu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}},
|
||||
{38, &JitIL::stX}, //"stb", OPTYPE_STORE, FL_IN_A | FL_IN_S}},
|
||||
{39, &JitIL::stX}, //"stbu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}},
|
||||
|
||||
{46, &JitIL::lmw}, //"lmw", OPTYPE_SYSTEM, FL_EVIL, 10}},
|
||||
{47, &JitIL::stmw}, //"stmw", OPTYPE_SYSTEM, FL_EVIL, 10}},
|
||||
|
||||
{48, &JitIL::lfs}, //"lfs", OPTYPE_LOADFP, FL_IN_A}},
|
||||
{49, &JitIL::lfsu}, //"lfsu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}},
|
||||
{50, &JitIL::lfd}, //"lfd", OPTYPE_LOADFP, FL_IN_A}},
|
||||
{51, &JitIL::lfdu}, //"lfdu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}},
|
||||
|
||||
{52, &JitIL::stfs}, //"stfs", OPTYPE_STOREFP, FL_IN_A}},
|
||||
{53, &JitIL::stfs}, //"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}},
|
||||
{54, &JitIL::stfd}, //"stfd", OPTYPE_STOREFP, FL_IN_A}},
|
||||
{55, &JitIL::stfd}, //"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}},
|
||||
|
||||
{56, &JitIL::psq_l}, //"psq_l", OPTYPE_PS, FL_IN_A}},
|
||||
{57, &JitIL::psq_l}, //"psq_lu", OPTYPE_PS, FL_OUT_A | FL_IN_A}},
|
||||
{60, &JitIL::psq_st}, //"psq_st", OPTYPE_PS, FL_IN_A}},
|
||||
{61, &JitIL::psq_st}, //"psq_stu", OPTYPE_PS, FL_OUT_A | FL_IN_A}},
|
||||
|
||||
// missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58
|
||||
};
|
||||
|
||||
const GekkoOPTemplate table4[] = {
|
||||
// SUBOP10
|
||||
{0, &JitIL::FallBackToInterpreter}, //"ps_cmpu0", OPTYPE_PS, FL_SET_CRn}},
|
||||
{32, &JitIL::FallBackToInterpreter}, //"ps_cmpo0", OPTYPE_PS, FL_SET_CRn}},
|
||||
{40, &JitIL::FallBackToInterpreter}, //"ps_neg", OPTYPE_PS, FL_RC_BIT}},
|
||||
{136, &JitIL::FallBackToInterpreter}, //"ps_nabs", OPTYPE_PS, FL_RC_BIT}},
|
||||
{264, &JitIL::FallBackToInterpreter}, //"ps_abs", OPTYPE_PS, FL_RC_BIT}},
|
||||
{64, &JitIL::FallBackToInterpreter}, //"ps_cmpu1", OPTYPE_PS, FL_RC_BIT}},
|
||||
{72, &JitIL::FallBackToInterpreter}, //"ps_mr", OPTYPE_PS, FL_RC_BIT}},
|
||||
{96, &JitIL::FallBackToInterpreter}, //"ps_cmpo1", OPTYPE_PS, FL_RC_BIT}},
|
||||
{528, &JitIL::ps_mergeXX}, //"ps_merge00", OPTYPE_PS, FL_RC_BIT}},
|
||||
{560, &JitIL::ps_mergeXX}, //"ps_merge01", OPTYPE_PS, FL_RC_BIT}},
|
||||
{592, &JitIL::ps_mergeXX}, //"ps_merge10", OPTYPE_PS, FL_RC_BIT}},
|
||||
{624, &JitIL::ps_mergeXX}, //"ps_merge11", OPTYPE_PS, FL_RC_BIT}},
|
||||
|
||||
{1014, &JitIL::FallBackToInterpreter}, //"dcbz_l", OPTYPE_SYSTEM, 0}},
|
||||
};
|
||||
|
||||
const GekkoOPTemplate table4_2[] = {
|
||||
{10, &JitIL::ps_sum}, //"ps_sum0", OPTYPE_PS, 0}},
|
||||
{11, &JitIL::ps_sum}, //"ps_sum1", OPTYPE_PS, 0}},
|
||||
{12, &JitIL::ps_muls}, //"ps_muls0", OPTYPE_PS, 0}},
|
||||
{13, &JitIL::ps_muls}, //"ps_muls1", OPTYPE_PS, 0}},
|
||||
{14, &JitIL::ps_maddXX}, //"ps_madds0", OPTYPE_PS, 0}},
|
||||
{15, &JitIL::ps_maddXX}, //"ps_madds1", OPTYPE_PS, 0}},
|
||||
{18, &JitIL::ps_arith}, //"ps_div", OPTYPE_PS, 0, 16}},
|
||||
{20, &JitIL::ps_arith}, //"ps_sub", OPTYPE_PS, 0}},
|
||||
{21, &JitIL::ps_arith}, //"ps_add", OPTYPE_PS, 0}},
|
||||
{23, &JitIL::FallBackToInterpreter}, //"ps_sel", OPTYPE_PS, 0}},
|
||||
{24, &JitIL::FallBackToInterpreter}, //"ps_res", OPTYPE_PS, 0}},
|
||||
{25, &JitIL::ps_arith}, //"ps_mul", OPTYPE_PS, 0}},
|
||||
{26, &JitIL::FallBackToInterpreter}, //"ps_rsqrte", OPTYPE_PS, 0, 1}},
|
||||
{28, &JitIL::ps_maddXX}, //"ps_msub", OPTYPE_PS, 0}},
|
||||
{29, &JitIL::ps_maddXX}, //"ps_madd", OPTYPE_PS, 0}},
|
||||
{30, &JitIL::ps_maddXX}, //"ps_nmsub", OPTYPE_PS, 0}},
|
||||
{31, &JitIL::ps_maddXX}, //"ps_nmadd", OPTYPE_PS, 0}},
|
||||
};
|
||||
|
||||
const GekkoOPTemplate table4_3[] = {
|
||||
{6, &JitIL::FallBackToInterpreter}, //"psq_lx", OPTYPE_PS, 0}},
|
||||
{7, &JitIL::FallBackToInterpreter}, //"psq_stx", OPTYPE_PS, 0}},
|
||||
{38, &JitIL::FallBackToInterpreter}, //"psq_lux", OPTYPE_PS, 0}},
|
||||
{39, &JitIL::FallBackToInterpreter}, //"psq_stux", OPTYPE_PS, 0}},
|
||||
};
|
||||
|
||||
const GekkoOPTemplate table19[] = {
|
||||
{528, &JitIL::bcctrx}, //"bcctrx", OPTYPE_BRANCH, FL_ENDBLOCK}},
|
||||
{16, &JitIL::bclrx}, //"bclrx", OPTYPE_BRANCH, FL_ENDBLOCK}},
|
||||
{257, &JitIL::crXX}, //"crand", OPTYPE_CR, FL_EVIL}},
|
||||
{129, &JitIL::crXX}, //"crandc", OPTYPE_CR, FL_EVIL}},
|
||||
{289, &JitIL::crXX}, //"creqv", OPTYPE_CR, FL_EVIL}},
|
||||
{225, &JitIL::crXX}, //"crnand", OPTYPE_CR, FL_EVIL}},
|
||||
{33, &JitIL::crXX}, //"crnor", OPTYPE_CR, FL_EVIL}},
|
||||
{449, &JitIL::crXX}, //"cror", OPTYPE_CR, FL_EVIL}},
|
||||
{417, &JitIL::crXX}, //"crorc", OPTYPE_CR, FL_EVIL}},
|
||||
{193, &JitIL::crXX}, //"crxor", OPTYPE_CR, FL_EVIL}},
|
||||
|
||||
{150, &JitIL::DoNothing}, //"isync", OPTYPE_ICACHE, FL_EVIL}},
|
||||
{0, &JitIL::mcrf}, //"mcrf", OPTYPE_SYSTEM, FL_EVIL}},
|
||||
|
||||
{50, &JitIL::rfi}, //"rfi", OPTYPE_SYSTEM, FL_ENDBLOCK | FL_CHECKEXCEPTIONS, 1}},
|
||||
};
|
||||
|
||||
const GekkoOPTemplate table31[] = {
|
||||
{266, &JitIL::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{778, &JitIL::addx}, //"addox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{10, &JitIL::FallBackToInterpreter}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB |
|
||||
// FL_SET_CA | FL_RC_BIT}},
|
||||
{522, &JitIL::FallBackToInterpreter}, //"addcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB |
|
||||
// FL_SET_CA | FL_RC_BIT}},
|
||||
{138, &JitIL::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA
|
||||
//| FL_RC_BIT}},
|
||||
{650, &JitIL::addex}, //"addeox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA
|
||||
//| FL_RC_BIT}},
|
||||
{234, &JitIL::FallBackToInterpreter}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB |
|
||||
// FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{746, &JitIL::FallBackToInterpreter}, //"addmeox"
|
||||
{202, &JitIL::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA |
|
||||
// FL_SET_CA | FL_RC_BIT}},
|
||||
{714, &JitIL::addzex}, //"addzeox"
|
||||
{491, &JitIL::FallBackToInterpreter}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB |
|
||||
// FL_RC_BIT, 39}},
|
||||
{1003, &JitIL::FallBackToInterpreter}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB |
|
||||
// FL_RC_BIT, 39}},
|
||||
{459, &JitIL::divwux}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{971, &JitIL::divwux}, //"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{75, &JitIL::FallBackToInterpreter}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB |
|
||||
// FL_RC_BIT, 4}},
|
||||
{11, &JitIL::mulhwux}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||
{235, &JitIL::mullwx}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||
{747, &JitIL::mullwx}, //"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||
{104, &JitIL::negx}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{616, &JitIL::negx}, //"negox"
|
||||
{40, &JitIL::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{552, &JitIL::subfx}, //"subfox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{8,
|
||||
&JitIL::subfcx}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{520,
|
||||
&JitIL::subfcx}, //"subfcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{136, &JitIL::subfex}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA |
|
||||
// FL_SET_CA | FL_RC_BIT}},
|
||||
{648, &JitIL::subfex}, //"subfeox"
|
||||
{232, &JitIL::FallBackToInterpreter}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB |
|
||||
// FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{744, &JitIL::FallBackToInterpreter}, //"subfmeox"
|
||||
{200, &JitIL::FallBackToInterpreter}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB |
|
||||
// FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{712, &JitIL::FallBackToInterpreter}, //"subfzeox"
|
||||
|
||||
{28, &JitIL::boolX}, //"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{60, &JitIL::boolX}, //"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{444, &JitIL::boolX}, //"orx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{124, &JitIL::boolX}, //"norx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{316, &JitIL::boolX}, //"xorx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{412, &JitIL::boolX}, //"orcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{476, &JitIL::boolX}, //"nandx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{284, &JitIL::boolX}, //"eqvx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}},
|
||||
{0, &JitIL::cmpXX}, //"cmp", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}},
|
||||
{32, &JitIL::cmpXX}, //"cmpl", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}},
|
||||
{26, &JitIL::cntlzwx}, //"cntlzwx",OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}},
|
||||
{922, &JitIL::extshx}, //"extshx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}},
|
||||
{954, &JitIL::extsbx}, //"extsbx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}},
|
||||
{536, &JitIL::srwx}, //"srwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
{792, &JitIL::srawx}, //"srawx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
{824, &JitIL::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
{24, &JitIL::slwx}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
|
||||
{54, &JitIL::dcbst}, //"dcbst", OPTYPE_DCACHE, 0, 4}},
|
||||
{86, &JitIL::FallBackToInterpreter}, //"dcbf", OPTYPE_DCACHE, 0, 4}},
|
||||
{246, &JitIL::DoNothing}, //"dcbtst", OPTYPE_DCACHE, 0, 1}},
|
||||
{278, &JitIL::DoNothing}, //"dcbt", OPTYPE_DCACHE, 0, 1}},
|
||||
{470, &JitIL::FallBackToInterpreter}, //"dcbi", OPTYPE_DCACHE, 0, 4}},
|
||||
{758, &JitIL::DoNothing}, //"dcba", OPTYPE_DCACHE, 0, 4}},
|
||||
{1014, &JitIL::dcbz}, //"dcbz", OPTYPE_DCACHE, 0, 4}},
|
||||
|
||||
// load word
|
||||
{23, &JitIL::lXzx}, //"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
{55, &JitIL::lXzx}, //"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
// load halfword
|
||||
{279, &JitIL::lXzx}, //"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
{311, &JitIL::lXzx}, //"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
// load halfword signextend
|
||||
{343, &JitIL::lhax}, //"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
{375, &JitIL::lhaux}, //"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
// load byte
|
||||
{87, &JitIL::lXzx}, //"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
{119, &JitIL::lXzx}, //"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
// load byte reverse
|
||||
{534, &JitIL::FallBackToInterpreter}, //"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
{790, &JitIL::FallBackToInterpreter}, //"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
|
||||
|
||||
// Conditional load/store (Wii SMP)
|
||||
{150, &JitIL::FallBackToInterpreter}, //"stwcxd", OPTYPE_STORE, FL_EVIL | FL_SET_CR0}},
|
||||
{20, &JitIL::FallBackToInterpreter}, //"lwarx", OPTYPE_LOAD, FL_EVIL | FL_OUT_D | FL_IN_A0B |
|
||||
// FL_SET_CR0}},
|
||||
|
||||
// load string (interpret these)
|
||||
{533, &JitIL::FallBackToInterpreter}, //"lswx", OPTYPE_LOAD, FL_EVIL | FL_IN_A | FL_OUT_D}},
|
||||
{597, &JitIL::FallBackToInterpreter}, //"lswi", OPTYPE_LOAD, FL_EVIL | FL_IN_AB | FL_OUT_D}},
|
||||
|
||||
// store word
|
||||
{151, &JitIL::stXx}, //"stwx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
|
||||
{183, &JitIL::stXx}, //"stwux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
// store halfword
|
||||
{407, &JitIL::stXx}, //"sthx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
|
||||
{439, &JitIL::stXx}, //"sthux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
// store byte
|
||||
{215, &JitIL::stXx}, //"stbx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
|
||||
{247, &JitIL::stXx}, //"stbux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}},
|
||||
|
||||
// store bytereverse
|
||||
{662, &JitIL::FallBackToInterpreter}, //"stwbrx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
|
||||
{918, &JitIL::FallBackToInterpreter}, //"sthbrx", OPTYPE_STORE, FL_IN_A | FL_IN_B}},
|
||||
|
||||
{661, &JitIL::FallBackToInterpreter}, //"stswx", OPTYPE_STORE, FL_EVIL}},
|
||||
{725, &JitIL::FallBackToInterpreter}, //"stswi", OPTYPE_STORE, FL_EVIL}},
|
||||
|
||||
// fp load/store
|
||||
{535, &JitIL::lfsx}, //"lfsx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}},
|
||||
{567, &JitIL::FallBackToInterpreter}, //"lfsux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}},
|
||||
{599, &JitIL::FallBackToInterpreter}, //"lfdx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}},
|
||||
{631, &JitIL::FallBackToInterpreter}, //"lfdux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}},
|
||||
|
||||
{663, &JitIL::stfsx}, //"stfsx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}},
|
||||
{695, &JitIL::FallBackToInterpreter}, //"stfsux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}},
|
||||
{727, &JitIL::FallBackToInterpreter}, //"stfdx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}},
|
||||
{759, &JitIL::FallBackToInterpreter}, //"stfdux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}},
|
||||
{983, &JitIL::FallBackToInterpreter}, //"stfiwx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}},
|
||||
|
||||
{19, &JitIL::mfcr}, //"mfcr", OPTYPE_SYSTEM, FL_OUT_D}},
|
||||
{83, &JitIL::mfmsr}, //"mfmsr", OPTYPE_SYSTEM, FL_OUT_D}},
|
||||
{144, &JitIL::mtcrf}, //"mtcrf", OPTYPE_SYSTEM, 0}},
|
||||
{146, &JitIL::mtmsr}, //"mtmsr", OPTYPE_SYSTEM, FL_ENDBLOCK}},
|
||||
{210, &JitIL::FallBackToInterpreter}, //"mtsr", OPTYPE_SYSTEM, 0}},
|
||||
{242, &JitIL::FallBackToInterpreter}, //"mtsrin", OPTYPE_SYSTEM, 0}},
|
||||
{339, &JitIL::mfspr}, //"mfspr", OPTYPE_SPR, FL_OUT_D}},
|
||||
{467, &JitIL::mtspr}, //"mtspr", OPTYPE_SPR, 0, 2}},
|
||||
{371, &JitIL::mftb}, //"mftb", OPTYPE_SYSTEM, FL_OUT_D | FL_TIMER}},
|
||||
{512, &JitIL::FallBackToInterpreter}, //"mcrxr", OPTYPE_SYSTEM, 0}},
|
||||
{595, &JitIL::FallBackToInterpreter}, //"mfsr", OPTYPE_SYSTEM, FL_OUT_D, 2}},
|
||||
{659, &JitIL::FallBackToInterpreter}, //"mfsrin", OPTYPE_SYSTEM, FL_OUT_D, 2}},
|
||||
|
||||
{4, &JitIL::FallBackToInterpreter}, //"tw", OPTYPE_SYSTEM, 0, 1}},
|
||||
{598, &JitIL::DoNothing}, //"sync", OPTYPE_SYSTEM, 0, 2}},
|
||||
{982, &JitIL::icbi}, //"icbi", OPTYPE_SYSTEM, FL_ENDBLOCK, 3}},
|
||||
|
||||
// Unused instructions on GC
|
||||
{310, &JitIL::FallBackToInterpreter}, //"eciwx", OPTYPE_INTEGER, FL_RC_BIT}},
|
||||
{438, &JitIL::FallBackToInterpreter}, //"ecowx", OPTYPE_INTEGER, FL_RC_BIT}},
|
||||
{854, &JitIL::DoNothing}, //"eieio", OPTYPE_INTEGER, FL_RC_BIT}},
|
||||
{306, &JitIL::FallBackToInterpreter}, //"tlbie", OPTYPE_SYSTEM, 0}},
|
||||
{566, &JitIL::DoNothing}, //"tlbsync", OPTYPE_SYSTEM, 0}},
|
||||
};
|
||||
|
||||
const GekkoOPTemplate table59[] = {
|
||||
{18, &JitIL::FallBackToInterpreter}, //{"fdivsx", OPTYPE_FPU, FL_RC_BIT_F, 16}},
|
||||
{20, &JitIL::fp_arith_s}, //"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{21, &JitIL::fp_arith_s}, //"faddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{24, &JitIL::FallBackToInterpreter}, //"fresx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{25, &JitIL::fp_arith_s}, //"fmulsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{28, &JitIL::fmaddXX}, //"fmsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{29, &JitIL::fmaddXX}, //"fmaddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{30, &JitIL::fmaddXX}, //"fnmsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{31, &JitIL::fmaddXX}, //"fnmaddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
};
|
||||
|
||||
const GekkoOPTemplate table63[] = {
|
||||
{264, &JitIL::fsign}, //"fabsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{32, &JitIL::fcmpX}, //"fcmpo", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{0, &JitIL::fcmpX}, //"fcmpu", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{14, &JitIL::FallBackToInterpreter}, //"fctiwx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{15, &JitIL::FallBackToInterpreter}, //"fctiwzx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{72, &JitIL::fmrx}, //"fmrx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{136, &JitIL::fsign}, //"fnabsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{40, &JitIL::fsign}, //"fnegx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{12, &JitIL::FallBackToInterpreter}, //"frspx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
|
||||
{64, &JitIL::FallBackToInterpreter}, //"mcrfs", OPTYPE_SYSTEMFP, 0}},
|
||||
{583, &JitIL::FallBackToInterpreter}, //"mffsx", OPTYPE_SYSTEMFP, 0}},
|
||||
{70, &JitIL::FallBackToInterpreter}, //"mtfsb0x", OPTYPE_SYSTEMFP, 0, 2}},
|
||||
{38, &JitIL::FallBackToInterpreter}, //"mtfsb1x", OPTYPE_SYSTEMFP, 0, 2}},
|
||||
{134, &JitIL::FallBackToInterpreter}, //"mtfsfix", OPTYPE_SYSTEMFP, 0, 2}},
|
||||
{711, &JitIL::FallBackToInterpreter}, //"mtfsfx", OPTYPE_SYSTEMFP, 0, 2}},
|
||||
};
|
||||
|
||||
const GekkoOPTemplate table63_2[] = {
|
||||
{18, &JitIL::FallBackToInterpreter}, //"fdivx", OPTYPE_FPU, FL_RC_BIT_F, 30}},
|
||||
{20, &JitIL::FallBackToInterpreter}, //"fsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{21, &JitIL::FallBackToInterpreter}, //"faddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{23, &JitIL::FallBackToInterpreter}, //"fselx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{25, &JitIL::fp_arith_s}, //"fmulx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{26, &JitIL::FallBackToInterpreter}, //"frsqrtex", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{28, &JitIL::fmaddXX}, //"fmsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{29, &JitIL::fmaddXX}, //"fmaddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{30, &JitIL::fmaddXX}, //"fnmsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{31, &JitIL::fmaddXX}, //"fnmaddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
};
|
||||
|
||||
void JitIL::CompileInstruction(PPCAnalyst::CodeOp& op)
|
||||
{
|
||||
(this->*dynaOpTable[op.inst.OPCD])(op.inst);
|
||||
|
||||
GekkoOPInfo* info = op.opinfo;
|
||||
if (info)
|
||||
{
|
||||
#ifdef OPLOG
|
||||
if (!strcmp(info->opname, OP_TO_LOG)) // "mcrfs"
|
||||
{
|
||||
rsplocations.push_back(js.compilerPC);
|
||||
}
|
||||
#endif
|
||||
info->compileCount++;
|
||||
info->lastUse = js.compilerPC;
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("Tried to compile illegal (or unknown) instruction %08x, at %08x", op.inst.hex,
|
||||
js.compilerPC);
|
||||
}
|
||||
}
|
||||
|
||||
void JitIL::InitializeInstructionTables()
|
||||
{
|
||||
// once initialized, tables are read-only
|
||||
static bool initialized = false;
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
// clear
|
||||
for (auto& tpl : dynaOpTable)
|
||||
{
|
||||
tpl = &JitIL::FallBackToInterpreter;
|
||||
}
|
||||
|
||||
for (auto& tpl : dynaOpTable59)
|
||||
{
|
||||
tpl = &JitIL::FallBackToInterpreter;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1024; i++)
|
||||
{
|
||||
dynaOpTable4[i] = &JitIL::FallBackToInterpreter;
|
||||
dynaOpTable19[i] = &JitIL::FallBackToInterpreter;
|
||||
dynaOpTable31[i] = &JitIL::FallBackToInterpreter;
|
||||
dynaOpTable63[i] = &JitIL::FallBackToInterpreter;
|
||||
}
|
||||
|
||||
for (const auto& tpl : primarytable)
|
||||
{
|
||||
dynaOpTable[tpl.opcode] = tpl.Inst;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
int fill = i << 5;
|
||||
for (const auto& tpl : table4_2)
|
||||
{
|
||||
int op = fill + tpl.opcode;
|
||||
dynaOpTable4[op] = tpl.Inst;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
int fill = i << 6;
|
||||
for (const auto& tpl : table4_3)
|
||||
{
|
||||
int op = fill + tpl.opcode;
|
||||
dynaOpTable4[op] = tpl.Inst;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& tpl : table4)
|
||||
{
|
||||
int op = tpl.opcode;
|
||||
dynaOpTable4[op] = tpl.Inst;
|
||||
}
|
||||
|
||||
for (const auto& tpl : table31)
|
||||
{
|
||||
int op = tpl.opcode;
|
||||
dynaOpTable31[op] = tpl.Inst;
|
||||
}
|
||||
|
||||
for (const auto& tpl : table19)
|
||||
{
|
||||
int op = tpl.opcode;
|
||||
dynaOpTable19[op] = tpl.Inst;
|
||||
}
|
||||
|
||||
for (const auto& tpl : table59)
|
||||
{
|
||||
int op = tpl.opcode;
|
||||
dynaOpTable59[op] = tpl.Inst;
|
||||
}
|
||||
|
||||
for (const auto& tpl : table63)
|
||||
{
|
||||
int op = tpl.opcode;
|
||||
dynaOpTable63[op] = tpl.Inst;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
int fill = i << 5;
|
||||
for (const auto& tpl : table63_2)
|
||||
{
|
||||
int op = fill + tpl.opcode;
|
||||
dynaOpTable63[op] = tpl.Inst;
|
||||
}
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,443 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/NonCopyable.h"
|
||||
|
||||
namespace IREmitter
|
||||
{
|
||||
enum Opcode
|
||||
{
|
||||
Nop = 0,
|
||||
|
||||
// "Zero-operand" operators
|
||||
// Register load operators
|
||||
LoadGReg,
|
||||
LoadLink,
|
||||
LoadCR,
|
||||
LoadCarry,
|
||||
LoadCTR,
|
||||
LoadMSR,
|
||||
LoadGQR,
|
||||
|
||||
// Unary operators
|
||||
// Integer unary operators
|
||||
SExt8,
|
||||
SExt16,
|
||||
BSwap32,
|
||||
BSwap16,
|
||||
Cntlzw, // Count leading zeros
|
||||
Not,
|
||||
Load8, // These loads zext
|
||||
Load16,
|
||||
Load32,
|
||||
// CR conversions
|
||||
ConvertFromFastCR,
|
||||
ConvertToFastCR,
|
||||
// Branches
|
||||
BranchUncond,
|
||||
// Register store operators
|
||||
StoreGReg,
|
||||
StoreCR,
|
||||
StoreLink,
|
||||
StoreCarry,
|
||||
StoreCTR,
|
||||
StoreMSR,
|
||||
StoreFPRF,
|
||||
StoreGQR,
|
||||
StoreSRR,
|
||||
// Branch conditions
|
||||
FastCRSOSet,
|
||||
FastCREQSet,
|
||||
FastCRGTSet,
|
||||
FastCRLTSet,
|
||||
// Arbitrary interpreter instruction
|
||||
FallBackToInterpreter,
|
||||
|
||||
// Binary operators
|
||||
// Commutative integer operators
|
||||
Add,
|
||||
Mul,
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
// Non-commutative integer operators
|
||||
MulHighUnsigned,
|
||||
Sub,
|
||||
Shl, // Note that shifts ignore bits above the bottom 5
|
||||
Shrl,
|
||||
Sarl,
|
||||
Rol,
|
||||
ICmpCRSigned, // CR for signed int compare
|
||||
ICmpCRUnsigned, // CR for unsigned int compare
|
||||
ICmpEq, // One if equal, zero otherwise
|
||||
ICmpNe,
|
||||
ICmpUgt, // One if op1 > op2, zero otherwise
|
||||
ICmpUlt,
|
||||
ICmpUge,
|
||||
ICmpUle,
|
||||
ICmpSgt, // One if op1 > op2, zero otherwise
|
||||
ICmpSlt,
|
||||
ICmpSge,
|
||||
ICmpSle, // Opposite of sgt
|
||||
|
||||
// Memory store operators
|
||||
Store8,
|
||||
Store16,
|
||||
Store32,
|
||||
BranchCond,
|
||||
// Floating-point
|
||||
// There are three floating-point formats: single, double,
|
||||
// and packed. For any operation where the format of the
|
||||
// operand isn't known, the ForceTo* operations are used;
|
||||
// these are folded into the appropriate conversion
|
||||
// (or no conversion) depending on the type of the operand.
|
||||
// The "mreg" format is a pair of doubles; this is the
|
||||
// most general possible represenation which is used
|
||||
// in the register state.
|
||||
// This might seem like overkill, but the semantics require
|
||||
// having the different formats.
|
||||
// FIXME: Check the accuracy of the mapping:
|
||||
// 1. Is paired arithmetic always rounded to single-precision
|
||||
// first, or does it do double-to-single like the
|
||||
// single-precision instructions?
|
||||
// 2. The implementation of madd is slightly off, and
|
||||
// the implementation of fmuls is very slightly off;
|
||||
// likely nothing cares, though.
|
||||
FResult_Start,
|
||||
LoadSingle,
|
||||
LoadDouble,
|
||||
LoadPaired, // This handles quantizers itself
|
||||
DoubleToSingle,
|
||||
DupSingleToMReg,
|
||||
DupSingleToPacked,
|
||||
InsertDoubleInMReg,
|
||||
ExpandPackedToMReg,
|
||||
CompactMRegToPacked,
|
||||
LoadFReg,
|
||||
LoadFRegDENToZero,
|
||||
FSMul,
|
||||
FSAdd,
|
||||
FSSub,
|
||||
FSNeg,
|
||||
FPAdd,
|
||||
FPMul,
|
||||
FPSub,
|
||||
FPNeg,
|
||||
FDMul,
|
||||
FDAdd,
|
||||
FDSub,
|
||||
FDNeg,
|
||||
FPMerge00,
|
||||
FPMerge01,
|
||||
FPMerge10,
|
||||
FPMerge11,
|
||||
FPDup0,
|
||||
FPDup1,
|
||||
FResult_End,
|
||||
StorePaired,
|
||||
StoreSingle,
|
||||
StoreDouble,
|
||||
StoreFReg,
|
||||
FDCmpCR,
|
||||
|
||||
// "Trinary" operators
|
||||
// FIXME: Need to change representation!
|
||||
// Select, // Equivalent to C "Op1 ? Op2 : Op3"
|
||||
|
||||
// Integer constants
|
||||
CInt16,
|
||||
CInt32,
|
||||
|
||||
// Funny PPC "branches"
|
||||
SystemCall,
|
||||
RFIExit,
|
||||
InterpreterBranch,
|
||||
|
||||
IdleBranch, // branch operation belonging to idle loop
|
||||
ShortIdleLoop, // Idle loop seen in homebrew like Wii mahjong,
|
||||
// just a branch
|
||||
|
||||
// used for exception checking, at least until someone
|
||||
// has a better idea of integrating it
|
||||
FPExceptionCheck,
|
||||
DSIExceptionCheck,
|
||||
ExtExceptionCheck,
|
||||
BreakPointCheck,
|
||||
// "Opcode" representing a register too far away to
|
||||
// reference directly; this is a size optimization
|
||||
Tramp,
|
||||
// "Opcode"s representing the start and end
|
||||
BlockStart,
|
||||
BlockEnd,
|
||||
|
||||
// used for debugging
|
||||
Int3
|
||||
};
|
||||
|
||||
using Inst = u32;
|
||||
using InstLoc = Inst*;
|
||||
|
||||
constexpr u32 getOpcode(Inst i)
|
||||
{
|
||||
return i & 255;
|
||||
}
|
||||
|
||||
constexpr bool isImm(Inst i)
|
||||
{
|
||||
return getOpcode(i) >= CInt16 && getOpcode(i) <= CInt32;
|
||||
}
|
||||
|
||||
constexpr bool isICmp(Inst i)
|
||||
{
|
||||
return getOpcode(i) >= ICmpEq && getOpcode(i) <= ICmpSle;
|
||||
}
|
||||
|
||||
constexpr bool isFResult(Inst i)
|
||||
{
|
||||
return getOpcode(i) > FResult_Start && getOpcode(i) < FResult_End;
|
||||
}
|
||||
|
||||
InstLoc inline getOp1(InstLoc i)
|
||||
{
|
||||
i = i - 1 - ((*i >> 8) & 255);
|
||||
|
||||
if (getOpcode(*i) == Tramp)
|
||||
{
|
||||
i = i - 1 - (*i >> 8);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
InstLoc inline getOp2(InstLoc i)
|
||||
{
|
||||
i = i - 1 - ((*i >> 16) & 255);
|
||||
|
||||
if (getOpcode(*i) == Tramp)
|
||||
{
|
||||
i = i - 1 - (*i >> 8);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
class IRBuilder final : private NonCopyable
|
||||
{
|
||||
public:
|
||||
IRBuilder();
|
||||
|
||||
void Reset();
|
||||
|
||||
InstLoc EmitIntConst(unsigned value) { return EmitIntConst64(value); }
|
||||
InstLoc EmitIntConst64(u64 value);
|
||||
|
||||
InstLoc EmitStoreLink(InstLoc val) { return FoldUOp(StoreLink, val); }
|
||||
InstLoc EmitBranchUncond(InstLoc val) { return FoldUOp(BranchUncond, val); }
|
||||
InstLoc EmitBranchCond(InstLoc check, InstLoc dest) { return FoldBiOp(BranchCond, check, dest); }
|
||||
InstLoc EmitIdleBranch(InstLoc check, InstLoc dest) { return FoldBiOp(IdleBranch, check, dest); }
|
||||
InstLoc EmitLoadCR(unsigned crreg) { return FoldZeroOp(LoadCR, crreg); }
|
||||
InstLoc EmitStoreCR(InstLoc value, unsigned crreg) { return FoldUOp(StoreCR, value, crreg); }
|
||||
InstLoc EmitLoadLink() { return FoldZeroOp(LoadLink, 0); }
|
||||
InstLoc EmitLoadMSR() { return FoldZeroOp(LoadMSR, 0); }
|
||||
InstLoc EmitStoreMSR(InstLoc val, InstLoc pc) { return FoldBiOp(StoreMSR, val, pc); }
|
||||
InstLoc EmitStoreFPRF(InstLoc value) { return FoldUOp(StoreFPRF, value); }
|
||||
InstLoc EmitLoadGReg(unsigned reg) { return FoldZeroOp(LoadGReg, reg); }
|
||||
InstLoc EmitStoreGReg(InstLoc value, unsigned reg) { return FoldUOp(StoreGReg, value, reg); }
|
||||
InstLoc EmitNot(InstLoc op1) { return FoldUOp(Not, op1); }
|
||||
InstLoc EmitAnd(InstLoc op1, InstLoc op2) { return FoldBiOp(And, op1, op2); }
|
||||
InstLoc EmitXor(InstLoc op1, InstLoc op2) { return FoldBiOp(Xor, op1, op2); }
|
||||
InstLoc EmitSub(InstLoc op1, InstLoc op2) { return FoldBiOp(Sub, op1, op2); }
|
||||
InstLoc EmitOr(InstLoc op1, InstLoc op2) { return FoldBiOp(Or, op1, op2); }
|
||||
InstLoc EmitAdd(InstLoc op1, InstLoc op2) { return FoldBiOp(Add, op1, op2); }
|
||||
InstLoc EmitMul(InstLoc op1, InstLoc op2) { return FoldBiOp(Mul, op1, op2); }
|
||||
InstLoc EmitMulHighUnsigned(InstLoc op1, InstLoc op2)
|
||||
{
|
||||
return FoldBiOp(MulHighUnsigned, op1, op2);
|
||||
}
|
||||
|
||||
InstLoc EmitRol(InstLoc op1, InstLoc op2) { return FoldBiOp(Rol, op1, op2); }
|
||||
InstLoc EmitShl(InstLoc op1, InstLoc op2) { return FoldBiOp(Shl, op1, op2); }
|
||||
InstLoc EmitShrl(InstLoc op1, InstLoc op2) { return FoldBiOp(Shrl, op1, op2); }
|
||||
InstLoc EmitSarl(InstLoc op1, InstLoc op2) { return FoldBiOp(Sarl, op1, op2); }
|
||||
InstLoc EmitLoadCTR() { return FoldZeroOp(LoadCTR, 0); }
|
||||
InstLoc EmitStoreCTR(InstLoc op1) { return FoldUOp(StoreCTR, op1); }
|
||||
InstLoc EmitICmpEq(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpEq, op1, op2); }
|
||||
InstLoc EmitICmpNe(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpNe, op1, op2); }
|
||||
InstLoc EmitICmpUgt(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpUgt, op1, op2); }
|
||||
InstLoc EmitICmpUlt(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpUlt, op1, op2); }
|
||||
InstLoc EmitICmpSgt(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpSgt, op1, op2); }
|
||||
InstLoc EmitICmpSlt(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpSlt, op1, op2); }
|
||||
InstLoc EmitICmpSge(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpSge, op1, op2); }
|
||||
InstLoc EmitICmpSle(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpSle, op1, op2); }
|
||||
InstLoc EmitLoad8(InstLoc op1) { return FoldUOp(Load8, op1); }
|
||||
InstLoc EmitLoad16(InstLoc op1) { return FoldUOp(Load16, op1); }
|
||||
InstLoc EmitLoad32(InstLoc op1) { return FoldUOp(Load32, op1); }
|
||||
InstLoc EmitStore8(InstLoc op1, InstLoc op2) { return FoldBiOp(Store8, op1, op2); }
|
||||
InstLoc EmitStore16(InstLoc op1, InstLoc op2) { return FoldBiOp(Store16, op1, op2); }
|
||||
InstLoc EmitStore32(InstLoc op1, InstLoc op2) { return FoldBiOp(Store32, op1, op2); }
|
||||
InstLoc EmitSExt16(InstLoc op1) { return FoldUOp(SExt16, op1); }
|
||||
InstLoc EmitSExt8(InstLoc op1) { return FoldUOp(SExt8, op1); }
|
||||
InstLoc EmitCntlzw(InstLoc op1) { return FoldUOp(Cntlzw, op1); }
|
||||
InstLoc EmitICmpCRSigned(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpCRSigned, op1, op2); }
|
||||
InstLoc EmitICmpCRUnsigned(InstLoc op1, InstLoc op2)
|
||||
{
|
||||
return FoldBiOp(ICmpCRUnsigned, op1, op2);
|
||||
}
|
||||
|
||||
InstLoc EmitConvertFromFastCR(InstLoc op1) { return FoldUOp(ConvertFromFastCR, op1); }
|
||||
InstLoc EmitConvertToFastCR(InstLoc op1) { return FoldUOp(ConvertToFastCR, op1); }
|
||||
InstLoc EmitFastCRSOSet(InstLoc op1) { return FoldUOp(FastCRSOSet, op1); }
|
||||
InstLoc EmitFastCREQSet(InstLoc op1) { return FoldUOp(FastCREQSet, op1); }
|
||||
InstLoc EmitFastCRLTSet(InstLoc op1) { return FoldUOp(FastCRLTSet, op1); }
|
||||
InstLoc EmitFastCRGTSet(InstLoc op1) { return FoldUOp(FastCRGTSet, op1); }
|
||||
InstLoc EmitFallBackToInterpreter(InstLoc op1, InstLoc op2)
|
||||
{
|
||||
return FoldBiOp(FallBackToInterpreter, op1, op2);
|
||||
}
|
||||
|
||||
InstLoc EmitInterpreterBranch() { return FoldZeroOp(InterpreterBranch, 0); }
|
||||
InstLoc EmitLoadCarry() { return FoldZeroOp(LoadCarry, 0); }
|
||||
InstLoc EmitStoreCarry(InstLoc op1) { return FoldUOp(StoreCarry, op1); }
|
||||
InstLoc EmitSystemCall(InstLoc pc) { return FoldUOp(SystemCall, pc); }
|
||||
InstLoc EmitFPExceptionCheck(InstLoc pc) { return EmitUOp(FPExceptionCheck, pc); }
|
||||
InstLoc EmitDSIExceptionCheck(InstLoc pc) { return EmitUOp(DSIExceptionCheck, pc); }
|
||||
InstLoc EmitExtExceptionCheck(InstLoc pc) { return EmitUOp(ExtExceptionCheck, pc); }
|
||||
InstLoc EmitBreakPointCheck(InstLoc pc) { return EmitUOp(BreakPointCheck, pc); }
|
||||
InstLoc EmitRFIExit() { return FoldZeroOp(RFIExit, 0); }
|
||||
InstLoc EmitShortIdleLoop(InstLoc pc) { return FoldUOp(ShortIdleLoop, pc); }
|
||||
InstLoc EmitLoadSingle(InstLoc addr) { return FoldUOp(LoadSingle, addr); }
|
||||
InstLoc EmitLoadDouble(InstLoc addr) { return FoldUOp(LoadDouble, addr); }
|
||||
InstLoc EmitLoadPaired(InstLoc addr, unsigned quantReg)
|
||||
{
|
||||
return FoldUOp(LoadPaired, addr, quantReg);
|
||||
}
|
||||
|
||||
InstLoc EmitStoreSingle(InstLoc value, InstLoc addr)
|
||||
{
|
||||
return FoldBiOp(StoreSingle, value, addr);
|
||||
}
|
||||
|
||||
InstLoc EmitStoreDouble(InstLoc value, InstLoc addr)
|
||||
{
|
||||
return FoldBiOp(StoreDouble, value, addr);
|
||||
}
|
||||
|
||||
InstLoc EmitStorePaired(InstLoc value, InstLoc addr, unsigned quantReg)
|
||||
{
|
||||
return FoldBiOp(StorePaired, value, addr, quantReg);
|
||||
}
|
||||
|
||||
InstLoc EmitLoadFReg(unsigned freg) { return FoldZeroOp(LoadFReg, freg); }
|
||||
InstLoc EmitLoadFRegDENToZero(unsigned freg) { return FoldZeroOp(LoadFRegDENToZero, freg); }
|
||||
InstLoc EmitStoreFReg(InstLoc val, unsigned freg) { return FoldUOp(StoreFReg, val, freg); }
|
||||
InstLoc EmitDupSingleToMReg(InstLoc val) { return FoldUOp(DupSingleToMReg, val); }
|
||||
InstLoc EmitDupSingleToPacked(InstLoc val) { return FoldUOp(DupSingleToPacked, val); }
|
||||
InstLoc EmitInsertDoubleInMReg(InstLoc val, InstLoc reg)
|
||||
{
|
||||
return FoldBiOp(InsertDoubleInMReg, val, reg);
|
||||
}
|
||||
|
||||
InstLoc EmitExpandPackedToMReg(InstLoc val) { return FoldUOp(ExpandPackedToMReg, val); }
|
||||
InstLoc EmitCompactMRegToPacked(InstLoc val) { return FoldUOp(CompactMRegToPacked, val); }
|
||||
InstLoc EmitFSMul(InstLoc op1, InstLoc op2) { return FoldBiOp(FSMul, op1, op2); }
|
||||
InstLoc EmitFSAdd(InstLoc op1, InstLoc op2) { return FoldBiOp(FSAdd, op1, op2); }
|
||||
InstLoc EmitFSSub(InstLoc op1, InstLoc op2) { return FoldBiOp(FSSub, op1, op2); }
|
||||
InstLoc EmitFSNeg(InstLoc op1) { return FoldUOp(FSNeg, op1); }
|
||||
InstLoc EmitFDMul(InstLoc op1, InstLoc op2) { return FoldBiOp(FDMul, op1, op2); }
|
||||
InstLoc EmitFDAdd(InstLoc op1, InstLoc op2) { return FoldBiOp(FDAdd, op1, op2); }
|
||||
InstLoc EmitFDSub(InstLoc op1, InstLoc op2) { return FoldBiOp(FDSub, op1, op2); }
|
||||
InstLoc EmitFDNeg(InstLoc op1) { return FoldUOp(FDNeg, op1); }
|
||||
InstLoc EmitFPAdd(InstLoc op1, InstLoc op2) { return FoldBiOp(FPAdd, op1, op2); }
|
||||
InstLoc EmitFPMul(InstLoc op1, InstLoc op2) { return FoldBiOp(FPMul, op1, op2); }
|
||||
InstLoc EmitFPSub(InstLoc op1, InstLoc op2) { return FoldBiOp(FPSub, op1, op2); }
|
||||
InstLoc EmitFPMerge00(InstLoc op1, InstLoc op2) { return FoldBiOp(FPMerge00, op1, op2); }
|
||||
InstLoc EmitFPMerge01(InstLoc op1, InstLoc op2) { return FoldBiOp(FPMerge01, op1, op2); }
|
||||
InstLoc EmitFPMerge10(InstLoc op1, InstLoc op2) { return FoldBiOp(FPMerge10, op1, op2); }
|
||||
InstLoc EmitFPMerge11(InstLoc op1, InstLoc op2) { return FoldBiOp(FPMerge11, op1, op2); }
|
||||
InstLoc EmitFPDup0(InstLoc op1) { return FoldUOp(FPDup0, op1); }
|
||||
InstLoc EmitFPDup1(InstLoc op1) { return FoldUOp(FPDup1, op1); }
|
||||
InstLoc EmitFPNeg(InstLoc op1) { return FoldUOp(FPNeg, op1); }
|
||||
InstLoc EmitDoubleToSingle(InstLoc op1) { return FoldUOp(DoubleToSingle, op1); }
|
||||
InstLoc EmitFDCmpCR(InstLoc op1, InstLoc op2, int ordered)
|
||||
{
|
||||
return FoldBiOp(FDCmpCR, op1, op2, ordered);
|
||||
}
|
||||
|
||||
InstLoc EmitLoadGQR(unsigned gqr) { return FoldZeroOp(LoadGQR, gqr); }
|
||||
InstLoc EmitStoreGQR(InstLoc op1, unsigned gqr) { return FoldUOp(StoreGQR, op1, gqr); }
|
||||
InstLoc EmitStoreSRR(InstLoc op1, unsigned srr) { return FoldUOp(StoreSRR, op1, srr); }
|
||||
InstLoc EmitINT3() { return FoldZeroOp(Int3, 0); }
|
||||
void StartBackPass() { curReadPtr = InstList.data() + InstList.size(); }
|
||||
void StartForwardPass() { curReadPtr = InstList.data(); }
|
||||
InstLoc ReadForward() { return curReadPtr++; }
|
||||
InstLoc ReadBackward() { return --curReadPtr; }
|
||||
InstLoc getFirstInst() { return InstList.data(); }
|
||||
size_t getNumInsts() const { return InstList.size(); }
|
||||
unsigned int GetImmValue(InstLoc I) const { return (u32)GetImmValue64(I); }
|
||||
u64 GetImmValue64(InstLoc I) const;
|
||||
void SetMarkUsed(InstLoc I);
|
||||
bool IsMarkUsed(InstLoc I) const;
|
||||
void WriteToFile(u64 codeHash);
|
||||
|
||||
private:
|
||||
void InvalidateCaches();
|
||||
|
||||
InstLoc EmitZeroOp(unsigned Opcode, unsigned extra);
|
||||
InstLoc EmitUOp(unsigned OpCode, InstLoc Op1, unsigned extra = 0);
|
||||
InstLoc EmitBiOp(unsigned OpCode, InstLoc Op1, InstLoc Op2, unsigned extra = 0);
|
||||
|
||||
InstLoc FoldAdd(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldSub(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldMul(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldMulHighUnsigned(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldAnd(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldOr(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldRol(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldShl(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldShrl(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldXor(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldBranchCond(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldICmp(unsigned Opcode, InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldICmpCRSigned(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldICmpCRUnsigned(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldDoubleBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2);
|
||||
|
||||
InstLoc FoldFallBackToInterpreter(InstLoc Op1, InstLoc Op2);
|
||||
|
||||
InstLoc FoldZeroOp(unsigned Opcode, unsigned extra);
|
||||
InstLoc FoldUOp(unsigned OpCode, InstLoc Op1, unsigned extra = 0);
|
||||
InstLoc FoldBiOp(unsigned OpCode, InstLoc Op1, InstLoc Op2, unsigned extra = 0);
|
||||
|
||||
unsigned ComputeKnownZeroBits(InstLoc I) const;
|
||||
|
||||
bool isSameValue(InstLoc Op1, InstLoc Op2) const;
|
||||
unsigned getComplexity(InstLoc I) const;
|
||||
unsigned getNumberOfOperands(InstLoc I) const;
|
||||
void simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2);
|
||||
bool maskedValueIsZero(InstLoc Op1, InstLoc Op2) const;
|
||||
InstLoc isNeg(InstLoc I) const;
|
||||
|
||||
std::vector<Inst> InstList; // FIXME: We must ensure this is continuous!
|
||||
std::vector<bool> MarkUsed; // Used for IRWriter
|
||||
std::vector<u64> ConstList;
|
||||
InstLoc curReadPtr;
|
||||
std::array<InstLoc, 32> GRegCache;
|
||||
std::array<InstLoc, 32> GRegCacheStore;
|
||||
std::array<InstLoc, 32> FRegCache;
|
||||
std::array<InstLoc, 32> FRegCacheStore;
|
||||
InstLoc CarryCache;
|
||||
InstLoc CarryCacheStore;
|
||||
InstLoc CTRCache;
|
||||
InstLoc CTRCacheStore;
|
||||
std::array<InstLoc, 8> CRCache;
|
||||
std::array<InstLoc, 8> CRCacheStore;
|
||||
};
|
||||
} // namespace IREmitter
|
|
@ -1,130 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Base.h"
|
||||
#include "Core/PowerPC/JitILCommon/IR.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
|
||||
class JitILBase : public Jitx86Base
|
||||
{
|
||||
public:
|
||||
JitILBase() : code_buffer(32000) {}
|
||||
~JitILBase() {}
|
||||
virtual void Jit(u32 em_address) = 0;
|
||||
|
||||
virtual const CommonAsmRoutinesBase* GetAsmRoutines() = 0;
|
||||
|
||||
// OPCODES
|
||||
virtual void FallBackToInterpreter(UGeckoInstruction inst) = 0;
|
||||
virtual void DoNothing(UGeckoInstruction inst) = 0;
|
||||
virtual void HLEFunction(UGeckoInstruction inst) = 0;
|
||||
|
||||
virtual void DynaRunTable4(UGeckoInstruction _inst) = 0;
|
||||
virtual void DynaRunTable19(UGeckoInstruction _inst) = 0;
|
||||
virtual void DynaRunTable31(UGeckoInstruction _inst) = 0;
|
||||
virtual void DynaRunTable59(UGeckoInstruction _inst) = 0;
|
||||
virtual void DynaRunTable63(UGeckoInstruction _inst) = 0;
|
||||
|
||||
// Branches
|
||||
void sc(UGeckoInstruction inst);
|
||||
void rfi(UGeckoInstruction inst);
|
||||
void bx(UGeckoInstruction inst);
|
||||
void bcx(UGeckoInstruction inst);
|
||||
void bcctrx(UGeckoInstruction inst);
|
||||
void bclrx(UGeckoInstruction inst);
|
||||
|
||||
// LoadStore
|
||||
void lXzx(UGeckoInstruction inst);
|
||||
void lhax(UGeckoInstruction inst);
|
||||
void lhaux(UGeckoInstruction inst);
|
||||
void stXx(UGeckoInstruction inst);
|
||||
void lmw(UGeckoInstruction inst);
|
||||
void stmw(UGeckoInstruction inst);
|
||||
void stX(UGeckoInstruction inst); // stw sth stb
|
||||
void lXz(UGeckoInstruction inst);
|
||||
void lbzu(UGeckoInstruction inst);
|
||||
void lha(UGeckoInstruction inst);
|
||||
void lhau(UGeckoInstruction inst);
|
||||
|
||||
// System Registers
|
||||
void mtspr(UGeckoInstruction inst);
|
||||
void mfspr(UGeckoInstruction inst);
|
||||
void mtmsr(UGeckoInstruction inst);
|
||||
void mfmsr(UGeckoInstruction inst);
|
||||
void mftb(UGeckoInstruction inst);
|
||||
void mtcrf(UGeckoInstruction inst);
|
||||
void mfcr(UGeckoInstruction inst);
|
||||
void mcrf(UGeckoInstruction inst);
|
||||
void crXX(UGeckoInstruction inst);
|
||||
|
||||
void dcbst(UGeckoInstruction inst);
|
||||
void dcbz(UGeckoInstruction inst);
|
||||
void icbi(UGeckoInstruction inst);
|
||||
|
||||
void addx(UGeckoInstruction inst);
|
||||
void boolX(UGeckoInstruction inst);
|
||||
void mulli(UGeckoInstruction inst);
|
||||
void mulhwux(UGeckoInstruction inst);
|
||||
void mullwx(UGeckoInstruction inst);
|
||||
void divwux(UGeckoInstruction inst);
|
||||
void srawix(UGeckoInstruction inst);
|
||||
void srawx(UGeckoInstruction inst);
|
||||
void addex(UGeckoInstruction inst);
|
||||
void addzex(UGeckoInstruction inst);
|
||||
|
||||
void extsbx(UGeckoInstruction inst);
|
||||
void extshx(UGeckoInstruction inst);
|
||||
|
||||
void reg_imm(UGeckoInstruction inst);
|
||||
|
||||
void ps_arith(UGeckoInstruction inst); // aggregate
|
||||
void ps_mergeXX(UGeckoInstruction inst);
|
||||
void ps_maddXX(UGeckoInstruction inst);
|
||||
void ps_sum(UGeckoInstruction inst);
|
||||
void ps_muls(UGeckoInstruction inst);
|
||||
|
||||
void fp_arith_s(UGeckoInstruction inst);
|
||||
|
||||
void fcmpX(UGeckoInstruction inst);
|
||||
void fmrx(UGeckoInstruction inst);
|
||||
|
||||
void cmpXX(UGeckoInstruction inst);
|
||||
|
||||
void cntlzwx(UGeckoInstruction inst);
|
||||
|
||||
void lfs(UGeckoInstruction inst);
|
||||
void lfsu(UGeckoInstruction inst);
|
||||
void lfd(UGeckoInstruction inst);
|
||||
void lfdu(UGeckoInstruction inst);
|
||||
void stfd(UGeckoInstruction inst);
|
||||
void stfs(UGeckoInstruction inst);
|
||||
void stfsx(UGeckoInstruction inst);
|
||||
void psq_l(UGeckoInstruction inst);
|
||||
void psq_st(UGeckoInstruction inst);
|
||||
|
||||
void fmaddXX(UGeckoInstruction inst);
|
||||
void fsign(UGeckoInstruction inst);
|
||||
void rlwinmx(UGeckoInstruction inst);
|
||||
void rlwimix(UGeckoInstruction inst);
|
||||
void rlwnmx(UGeckoInstruction inst);
|
||||
void negx(UGeckoInstruction inst);
|
||||
void slwx(UGeckoInstruction inst);
|
||||
void srwx(UGeckoInstruction inst);
|
||||
void lfsx(UGeckoInstruction inst);
|
||||
|
||||
void subfic(UGeckoInstruction inst);
|
||||
void subfcx(UGeckoInstruction inst);
|
||||
void subfx(UGeckoInstruction inst);
|
||||
void subfex(UGeckoInstruction inst);
|
||||
|
||||
protected:
|
||||
// The default code buffer. We keep it around to not have to alloc/dealloc a
|
||||
// large chunk of memory for each recompiled block.
|
||||
PPCAnalyst::CodeBuffer code_buffer;
|
||||
IREmitter::IRBuilder ibuild;
|
||||
};
|
|
@ -1,217 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/JitILCommon/JitILBase.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
// The branches are known good, or at least reasonably good.
|
||||
// No need for a disable-mechanism.
|
||||
|
||||
// If defined, clears CR0 at blr and bl-s. If the assumption that
|
||||
// flags never carry over between functions holds, then the task for
|
||||
// an optimizer becomes much easier.
|
||||
|
||||
// #define ACID_TEST
|
||||
|
||||
// Zelda and many more games seem to pass the Acid Test.
|
||||
|
||||
//#define NORMALBRANCH_START FallBackToInterpreter(inst); ibuild.EmitInterpreterBranch(); return;
|
||||
#define NORMALBRANCH_START
|
||||
|
||||
void JitILBase::sc(UGeckoInstruction inst)
|
||||
{
|
||||
ibuild.EmitSystemCall(ibuild.EmitIntConst(js.compilerPC));
|
||||
}
|
||||
|
||||
void JitILBase::rfi(UGeckoInstruction inst)
|
||||
{
|
||||
ibuild.EmitRFIExit();
|
||||
}
|
||||
|
||||
void JitILBase::bx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
INSTRUCTION_START;
|
||||
|
||||
// We must always process the following sentence
|
||||
// even if the blocks are merged by PPCAnalyst::Flatten().
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
|
||||
// If this is not the last instruction of a block,
|
||||
// we will skip the rest process.
|
||||
// Because PPCAnalyst::Flatten() merged the blocks.
|
||||
if (!js.isLastInstruction)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
u32 destination;
|
||||
if (inst.AA)
|
||||
destination = SignExt26(inst.LI << 2);
|
||||
else
|
||||
destination = js.compilerPC + SignExt26(inst.LI << 2);
|
||||
|
||||
if (destination == js.compilerPC)
|
||||
{
|
||||
ibuild.EmitShortIdleLoop(ibuild.EmitIntConst(js.compilerPC));
|
||||
return;
|
||||
}
|
||||
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination));
|
||||
}
|
||||
|
||||
static IREmitter::InstLoc EmitCRTest(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst)
|
||||
{
|
||||
IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2);
|
||||
IREmitter::InstLoc CRTest = nullptr;
|
||||
switch (3 - (inst.BI & 3))
|
||||
{
|
||||
case CR_SO_BIT:
|
||||
CRTest = ibuild.EmitFastCRSOSet(CRReg);
|
||||
break;
|
||||
case CR_EQ_BIT:
|
||||
CRTest = ibuild.EmitFastCREQSet(CRReg);
|
||||
break;
|
||||
case CR_GT_BIT:
|
||||
CRTest = ibuild.EmitFastCRGTSet(CRReg);
|
||||
break;
|
||||
case CR_LT_BIT:
|
||||
CRTest = ibuild.EmitFastCRLTSet(CRReg);
|
||||
break;
|
||||
}
|
||||
if (!(inst.BO & 8))
|
||||
CRTest = ibuild.EmitXor(CRTest, ibuild.EmitIntConst(1));
|
||||
return CRTest;
|
||||
}
|
||||
|
||||
static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst)
|
||||
{
|
||||
IREmitter::InstLoc CRTest = nullptr, CTRTest = nullptr;
|
||||
if ((inst.BO & 16) == 0) // Test a CR bit
|
||||
{
|
||||
CRTest = EmitCRTest(ibuild, inst);
|
||||
}
|
||||
|
||||
if ((inst.BO & 4) == 0)
|
||||
{
|
||||
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
|
||||
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
|
||||
ibuild.EmitStoreCTR(c);
|
||||
|
||||
if (inst.BO & 2)
|
||||
CTRTest = ibuild.EmitICmpEq(c, ibuild.EmitIntConst(0));
|
||||
else
|
||||
CTRTest = c;
|
||||
}
|
||||
|
||||
IREmitter::InstLoc Test = CRTest;
|
||||
if (CTRTest)
|
||||
{
|
||||
if (Test)
|
||||
Test = ibuild.EmitAnd(Test, CTRTest);
|
||||
else
|
||||
Test = CTRTest;
|
||||
}
|
||||
|
||||
if (!Test)
|
||||
{
|
||||
Test = ibuild.EmitIntConst(1);
|
||||
}
|
||||
|
||||
return Test;
|
||||
}
|
||||
|
||||
void JitILBase::bcx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
|
||||
IREmitter::InstLoc Test = TestBranch(ibuild, inst);
|
||||
|
||||
u32 destination;
|
||||
if (inst.AA)
|
||||
destination = SignExt16(inst.BD << 2);
|
||||
else
|
||||
destination = js.compilerPC + SignExt16(inst.BD << 2);
|
||||
|
||||
// Idle skipping:
|
||||
// The main Idle skipping is done in the LoadStore code, but there is an optimization here.
|
||||
// If idle skipping is enabled, then this branch will only be reached when the branch is not
|
||||
// taken.
|
||||
// TODO: We shouldn't use debug reads here.
|
||||
if (inst.hex == 0x4182fff8 &&
|
||||
(PowerPC::HostRead_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 &&
|
||||
(PowerPC::HostRead_U32(js.compilerPC - 4) == 0x28000000 ||
|
||||
(SConfig::GetInstance().bWii && PowerPC::HostRead_U32(js.compilerPC - 4) == 0x2C000000)))
|
||||
{
|
||||
// Uh, Do nothing.
|
||||
}
|
||||
else
|
||||
{
|
||||
ibuild.EmitBranchCond(Test, ibuild.EmitIntConst(destination));
|
||||
}
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
}
|
||||
|
||||
void JitILBase::bcctrx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
if ((inst.BO & 4) == 0)
|
||||
{
|
||||
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
|
||||
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
|
||||
ibuild.EmitStoreCTR(c);
|
||||
}
|
||||
|
||||
IREmitter::InstLoc test;
|
||||
if ((inst.BO & 16) == 0) // Test a CR bit
|
||||
{
|
||||
test = EmitCRTest(ibuild, inst);
|
||||
}
|
||||
else
|
||||
{
|
||||
test = ibuild.EmitIntConst(1);
|
||||
}
|
||||
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
|
||||
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
|
||||
IREmitter::InstLoc destination = ibuild.EmitLoadCTR();
|
||||
destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4));
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
ibuild.EmitBranchUncond(destination);
|
||||
}
|
||||
|
||||
void JitILBase::bclrx(UGeckoInstruction inst)
|
||||
{
|
||||
NORMALBRANCH_START
|
||||
|
||||
if (!js.isLastInstruction && (inst.BO & (1 << 4)) && (inst.BO & (1 << 2)))
|
||||
{
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
return;
|
||||
}
|
||||
|
||||
if (inst.hex == 0x4e800020)
|
||||
{
|
||||
ibuild.EmitBranchUncond(ibuild.EmitLoadLink());
|
||||
return;
|
||||
}
|
||||
|
||||
IREmitter::InstLoc test = TestBranch(ibuild, inst);
|
||||
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
|
||||
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
|
||||
IREmitter::InstLoc destination = ibuild.EmitLoadLink();
|
||||
destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4));
|
||||
if (inst.LK)
|
||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
ibuild.EmitBranchUncond(destination);
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/JitILCommon/JitILBase.h"
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
|
||||
void JitILBase::fp_arith_s(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff);
|
||||
FALLBACK_IF(inst.Rc || (inst.SUBOP5 != 25 && inst.SUBOP5 != 20 && inst.SUBOP5 != 21));
|
||||
|
||||
// Only the interpreter has "proper" support for (some) FP flags
|
||||
FALLBACK_IF(inst.SUBOP5 == 25 && SConfig::GetInstance().bFPRF);
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
|
||||
switch (inst.SUBOP5)
|
||||
{
|
||||
case 20: // sub
|
||||
val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB));
|
||||
break;
|
||||
case 21: // add
|
||||
val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB));
|
||||
break;
|
||||
case 25: // mul
|
||||
val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC));
|
||||
break;
|
||||
default:
|
||||
_assert_msg_(DYNA_REC, 0, "fp_arith_s WTF!!!");
|
||||
}
|
||||
|
||||
if (inst.OPCD == 59)
|
||||
{
|
||||
val = ibuild.EmitDoubleToSingle(val);
|
||||
val = ibuild.EmitDupSingleToMReg(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
|
||||
}
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
void JitILBase::fmaddXX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff);
|
||||
FALLBACK_IF(inst.Rc);
|
||||
|
||||
// Only the interpreter has "proper" support for (some) FP flags
|
||||
FALLBACK_IF(inst.SUBOP5 == 29 && SConfig::GetInstance().bFPRF);
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
|
||||
val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC));
|
||||
|
||||
if (inst.SUBOP5 & 1)
|
||||
val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB));
|
||||
else
|
||||
val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB));
|
||||
|
||||
if (inst.SUBOP5 & 2)
|
||||
val = ibuild.EmitFDNeg(val);
|
||||
|
||||
if (inst.OPCD == 59)
|
||||
{
|
||||
val = ibuild.EmitDoubleToSingle(val);
|
||||
val = ibuild.EmitDupSingleToMReg(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
|
||||
}
|
||||
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
void JitILBase::fmrx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff);
|
||||
FALLBACK_IF(inst.Rc);
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FB);
|
||||
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
void JitILBase::fcmpX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff);
|
||||
IREmitter::InstLoc lhs, rhs, res;
|
||||
lhs = ibuild.EmitLoadFReg(inst.FA);
|
||||
rhs = ibuild.EmitLoadFReg(inst.FB);
|
||||
int ordered = (inst.SUBOP10 == 32) ? 1 : 0;
|
||||
res = ibuild.EmitFDCmpCR(lhs, rhs, ordered);
|
||||
ibuild.EmitStoreFPRF(res);
|
||||
ibuild.EmitStoreCR(ibuild.EmitConvertToFastCR(res), inst.CRFD);
|
||||
}
|
||||
|
||||
void JitILBase::fsign(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff);
|
||||
|
||||
FALLBACK_IF(true);
|
||||
|
||||
// TODO
|
||||
switch (inst.SUBOP10)
|
||||
{
|
||||
case 40: // fnegx
|
||||
break;
|
||||
case 264: // fabsx
|
||||
break;
|
||||
case 136: // fnabs
|
||||
break;
|
||||
default:
|
||||
PanicAlert("fsign bleh");
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,559 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( \
|
||||
disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
#endif
|
||||
|
||||
#include "Core/PowerPC/JitILCommon/JitILBase.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
static void ComputeRC(IREmitter::IRBuilder& ibuild, IREmitter::InstLoc val)
|
||||
{
|
||||
IREmitter::InstLoc res = ibuild.EmitICmpCRSigned(val, ibuild.EmitIntConst(0));
|
||||
ibuild.EmitStoreCR(res, 0);
|
||||
}
|
||||
|
||||
void JitILBase::reg_imm(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
int d = inst.RD, a = inst.RA, s = inst.RS;
|
||||
IREmitter::InstLoc val, test, c;
|
||||
switch (inst.OPCD)
|
||||
{
|
||||
case 14: // addi
|
||||
val = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
if (a)
|
||||
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
|
||||
ibuild.EmitStoreGReg(val, d);
|
||||
break;
|
||||
case 15: // addis
|
||||
val = ibuild.EmitIntConst(inst.SIMM_16 << 16);
|
||||
if (a)
|
||||
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
|
||||
ibuild.EmitStoreGReg(val, d);
|
||||
break;
|
||||
case 24: // ori
|
||||
val = ibuild.EmitIntConst(inst.UIMM);
|
||||
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
|
||||
ibuild.EmitStoreGReg(val, a);
|
||||
break;
|
||||
case 25: // oris
|
||||
val = ibuild.EmitIntConst(inst.UIMM << 16);
|
||||
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
|
||||
ibuild.EmitStoreGReg(val, a);
|
||||
break;
|
||||
case 28: // andi
|
||||
val = ibuild.EmitIntConst(inst.UIMM);
|
||||
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
|
||||
ibuild.EmitStoreGReg(val, a);
|
||||
ComputeRC(ibuild, val);
|
||||
break;
|
||||
case 29: // andis
|
||||
val = ibuild.EmitIntConst(inst.UIMM << 16);
|
||||
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
|
||||
ibuild.EmitStoreGReg(val, a);
|
||||
ComputeRC(ibuild, val);
|
||||
break;
|
||||
case 26: // xori
|
||||
val = ibuild.EmitIntConst(inst.UIMM);
|
||||
val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val);
|
||||
ibuild.EmitStoreGReg(val, a);
|
||||
break;
|
||||
case 27: // xoris
|
||||
val = ibuild.EmitIntConst(inst.UIMM << 16);
|
||||
val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val);
|
||||
ibuild.EmitStoreGReg(val, a);
|
||||
break;
|
||||
case 12: // addic
|
||||
case 13: // addic_rc
|
||||
c = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), c);
|
||||
ibuild.EmitStoreGReg(val, d);
|
||||
test = ibuild.EmitICmpUgt(c, val);
|
||||
ibuild.EmitStoreCarry(test);
|
||||
if (inst.OPCD == 13)
|
||||
ComputeRC(ibuild, val);
|
||||
break;
|
||||
default:
|
||||
FALLBACK_IF(true);
|
||||
}
|
||||
}
|
||||
|
||||
void JitILBase::cmpXX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
IREmitter::InstLoc lhs, rhs, res;
|
||||
lhs = ibuild.EmitLoadGReg(inst.RA);
|
||||
|
||||
if (inst.OPCD == 31)
|
||||
{
|
||||
rhs = ibuild.EmitLoadGReg(inst.RB);
|
||||
if (inst.SUBOP10 == 32)
|
||||
{
|
||||
res = ibuild.EmitICmpCRUnsigned(lhs, rhs);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ibuild.EmitICmpCRSigned(lhs, rhs);
|
||||
}
|
||||
}
|
||||
else if (inst.OPCD == 10)
|
||||
{
|
||||
rhs = ibuild.EmitIntConst(inst.UIMM);
|
||||
res = ibuild.EmitICmpCRUnsigned(lhs, rhs);
|
||||
}
|
||||
else // inst.OPCD == 11
|
||||
{
|
||||
rhs = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
res = ibuild.EmitICmpCRSigned(lhs, rhs);
|
||||
}
|
||||
|
||||
js.downcountAmount++; // TODO: should this be somewhere else?
|
||||
|
||||
ibuild.EmitStoreCR(res, inst.CRFD);
|
||||
}
|
||||
|
||||
void JitILBase::boolX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
|
||||
IREmitter::InstLoc a = nullptr;
|
||||
IREmitter::InstLoc s = ibuild.EmitLoadGReg(inst.RS);
|
||||
IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB);
|
||||
|
||||
// FIXME: Some instructions does not work well in NSMBW, MP2, etc.
|
||||
// Refer JitIL_Tables.cpp.
|
||||
if (inst.SUBOP10 == 28) /* andx */
|
||||
{
|
||||
a = ibuild.EmitAnd(s, b);
|
||||
}
|
||||
else if (inst.SUBOP10 == 476) /* nandx */
|
||||
{
|
||||
a = ibuild.EmitNot(ibuild.EmitAnd(s, b));
|
||||
}
|
||||
else if (inst.SUBOP10 == 60) /* andcx */
|
||||
{
|
||||
a = ibuild.EmitAnd(s, ibuild.EmitNot(b));
|
||||
}
|
||||
else if (inst.SUBOP10 == 444) /* orx */
|
||||
{
|
||||
a = ibuild.EmitOr(s, b);
|
||||
}
|
||||
else if (inst.SUBOP10 == 124) /* norx */
|
||||
{
|
||||
a = ibuild.EmitNot(ibuild.EmitOr(s, b));
|
||||
}
|
||||
else if (inst.SUBOP10 == 412) /* orcx */
|
||||
{
|
||||
a = ibuild.EmitOr(s, ibuild.EmitNot(b));
|
||||
}
|
||||
else if (inst.SUBOP10 == 316) /* xorx */
|
||||
{
|
||||
a = ibuild.EmitXor(s, b);
|
||||
}
|
||||
else if (inst.SUBOP10 == 284) /* eqvx */
|
||||
{
|
||||
a = ibuild.EmitNot(ibuild.EmitXor(s, b));
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("WTF!");
|
||||
}
|
||||
|
||||
ibuild.EmitStoreGReg(a, inst.RA);
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, a);
|
||||
}
|
||||
|
||||
void JitILBase::extsbx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||
val = ibuild.EmitSExt8(val);
|
||||
ibuild.EmitStoreGReg(val, inst.RA);
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::extshx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||
val = ibuild.EmitSExt16(val);
|
||||
ibuild.EmitStoreGReg(val, inst.RA);
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::subfic(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
IREmitter::InstLoc nota, lhs, val, test;
|
||||
nota = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RA), ibuild.EmitIntConst(-1));
|
||||
|
||||
if (inst.SIMM_16 == -1)
|
||||
{
|
||||
val = nota;
|
||||
test = ibuild.EmitIntConst(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
lhs = ibuild.EmitIntConst(inst.SIMM_16 + 1);
|
||||
val = ibuild.EmitAdd(nota, lhs);
|
||||
test = ibuild.EmitICmpUgt(lhs, val);
|
||||
}
|
||||
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
ibuild.EmitStoreCarry(test);
|
||||
}
|
||||
|
||||
void JitILBase::subfcx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
|
||||
if (inst.OE)
|
||||
PanicAlert("OE: subfcx");
|
||||
|
||||
IREmitter::InstLoc val, test, lhs, rhs;
|
||||
lhs = ibuild.EmitLoadGReg(inst.RB);
|
||||
rhs = ibuild.EmitLoadGReg(inst.RA);
|
||||
val = ibuild.EmitSub(lhs, rhs);
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0));
|
||||
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
|
||||
ibuild.EmitStoreCarry(test);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::subfex(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
|
||||
if (inst.OE)
|
||||
PanicAlert("OE: subfex");
|
||||
|
||||
IREmitter::InstLoc val, test, lhs, rhs, carry;
|
||||
rhs = ibuild.EmitLoadGReg(inst.RA);
|
||||
carry = ibuild.EmitLoadCarry();
|
||||
rhs = ibuild.EmitXor(rhs, ibuild.EmitIntConst(-1));
|
||||
rhs = ibuild.EmitAdd(rhs, carry);
|
||||
test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0));
|
||||
test = ibuild.EmitAnd(test, carry);
|
||||
lhs = ibuild.EmitLoadGReg(inst.RB);
|
||||
val = ibuild.EmitAdd(lhs, rhs);
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
|
||||
ibuild.EmitStoreCarry(test);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::subfx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
|
||||
if (inst.OE)
|
||||
PanicAlert("OE: subfx");
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
||||
val = ibuild.EmitSub(val, ibuild.EmitLoadGReg(inst.RA));
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::mulli(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
|
||||
val = ibuild.EmitMul(val, ibuild.EmitIntConst(inst.SIMM_16));
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
}
|
||||
|
||||
void JitILBase::mullwx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
||||
val = ibuild.EmitMul(ibuild.EmitLoadGReg(inst.RA), val);
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::mulhwux(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
|
||||
IREmitter::InstLoc a = ibuild.EmitLoadGReg(inst.RA);
|
||||
IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB);
|
||||
IREmitter::InstLoc d = ibuild.EmitMulHighUnsigned(a, b);
|
||||
ibuild.EmitStoreGReg(d, inst.RD);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, d);
|
||||
}
|
||||
|
||||
// skipped some of the special handling in here - if we get crashes, let the interpreter handle this
|
||||
// op
|
||||
void JitILBase::divwux(UGeckoInstruction inst)
|
||||
{
|
||||
// FIXME
|
||||
FALLBACK_IF(true);
|
||||
|
||||
#if 0
|
||||
int a = inst.RA, b = inst.RB, d = inst.RD;
|
||||
gpr.FlushLockX(RSCRATCH1);
|
||||
gpr.Lock(a, b, d);
|
||||
|
||||
if (d != a && d != b)
|
||||
{
|
||||
gpr.LoadToX64(d, false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
gpr.LoadToX64(d, true, true);
|
||||
}
|
||||
|
||||
MOV(32, R(RSCRATCH), gpr.R(a));
|
||||
XOR(32, R(RSCRATCH2), R(RSCRATCH));
|
||||
gpr.KillImmediate(b);
|
||||
DIV(32, gpr.R(b));
|
||||
MOV(32, gpr.R(d), R(RSCRATCH));
|
||||
gpr.UnlockAll();
|
||||
gpr.UnlockAllX();
|
||||
|
||||
if (inst.Rc)
|
||||
{
|
||||
CALL((u8*)asm_routines.computeRc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void JitILBase::addx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
||||
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), val);
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::addzex(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
IREmitter::InstLoc lhs = ibuild.EmitLoadGReg(inst.RA), val, newcarry;
|
||||
val = ibuild.EmitAdd(lhs, ibuild.EmitLoadCarry());
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
newcarry = ibuild.EmitICmpUlt(val, lhs);
|
||||
ibuild.EmitStoreCarry(newcarry);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::addex(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
|
||||
IREmitter::InstLoc a = ibuild.EmitLoadGReg(inst.RA);
|
||||
IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB);
|
||||
|
||||
IREmitter::InstLoc ab = ibuild.EmitAdd(a, b);
|
||||
IREmitter::InstLoc new_carry = ibuild.EmitICmpUlt(ab, a);
|
||||
|
||||
IREmitter::InstLoc previous_carry = ibuild.EmitLoadCarry();
|
||||
IREmitter::InstLoc abc = ibuild.EmitAdd(ab, previous_carry);
|
||||
new_carry = ibuild.EmitOr(new_carry, ibuild.EmitICmpUlt(abc, ab));
|
||||
|
||||
ibuild.EmitStoreGReg(abc, inst.RD);
|
||||
ibuild.EmitStoreCarry(new_carry);
|
||||
|
||||
if (inst.OE)
|
||||
PanicAlert("OE: addex");
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, abc);
|
||||
}
|
||||
|
||||
void JitILBase::rlwinmx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
unsigned mask = Helper_Mask(inst.MB, inst.ME);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
|
||||
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
||||
ibuild.EmitStoreGReg(val, inst.RA);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::rlwimix(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
unsigned mask = Helper_Mask(inst.MB, inst.ME);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
|
||||
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
||||
IREmitter::InstLoc ival = ibuild.EmitLoadGReg(inst.RA);
|
||||
ival = ibuild.EmitAnd(ival, ibuild.EmitIntConst(~mask));
|
||||
val = ibuild.EmitOr(ival, val);
|
||||
ibuild.EmitStoreGReg(val, inst.RA);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::rlwnmx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
unsigned int mask = Helper_Mask(inst.MB, inst.ME);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||
val = ibuild.EmitRol(val, ibuild.EmitLoadGReg(inst.RB));
|
||||
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
||||
ibuild.EmitStoreGReg(val, inst.RA);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::negx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
|
||||
val = ibuild.EmitSub(ibuild.EmitIntConst(0), val);
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::srwx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||
IREmitter::InstLoc samt = ibuild.EmitLoadGReg(inst.RB);
|
||||
IREmitter::InstLoc corr;
|
||||
|
||||
// FIXME: We can do better with a cmov
|
||||
// FIXME: We can do better on 64-bit
|
||||
val = ibuild.EmitShrl(val, samt);
|
||||
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
|
||||
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
|
||||
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
|
||||
val = ibuild.EmitAnd(corr, val);
|
||||
ibuild.EmitStoreGReg(val, inst.RA);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::slwx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||
IREmitter::InstLoc samt = ibuild.EmitLoadGReg(inst.RB);
|
||||
IREmitter::InstLoc corr;
|
||||
|
||||
// FIXME: We can do better with a cmov
|
||||
// FIXME: We can do better on 64-bit
|
||||
val = ibuild.EmitShl(val, samt);
|
||||
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
|
||||
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
|
||||
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
|
||||
val = ibuild.EmitAnd(corr, val);
|
||||
ibuild.EmitStoreGReg(val, inst.RA);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::srawx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
// FIXME: We can do a lot better on 64-bit
|
||||
IREmitter::InstLoc val, samt, mask, mask2, test;
|
||||
val = ibuild.EmitLoadGReg(inst.RS);
|
||||
samt = ibuild.EmitLoadGReg(inst.RB);
|
||||
mask = ibuild.EmitIntConst(-1);
|
||||
val = ibuild.EmitSarl(val, samt);
|
||||
mask = ibuild.EmitShl(mask, samt);
|
||||
samt = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
|
||||
samt = ibuild.EmitSarl(samt, ibuild.EmitIntConst(31));
|
||||
samt = ibuild.EmitAnd(samt, ibuild.EmitIntConst(31));
|
||||
val = ibuild.EmitSarl(val, samt);
|
||||
ibuild.EmitStoreGReg(val, inst.RA);
|
||||
mask = ibuild.EmitShl(mask, samt);
|
||||
mask2 = ibuild.EmitAnd(mask, ibuild.EmitIntConst(0x7FFFFFFF));
|
||||
test = ibuild.EmitOr(val, mask2);
|
||||
test = ibuild.EmitICmpUgt(test, mask);
|
||||
ibuild.EmitStoreCarry(test);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitILBase::srawix(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
// Shift right by two
|
||||
IREmitter::InstLoc input = ibuild.EmitLoadGReg(inst.RS);
|
||||
IREmitter::InstLoc output = ibuild.EmitSarl(input, ibuild.EmitIntConst(inst.SH));
|
||||
ibuild.EmitStoreGReg(output, inst.RA);
|
||||
// Check whether the input is negative and any bits got shifted out.
|
||||
unsigned int mask = -1u << inst.SH;
|
||||
IREmitter::InstLoc test = ibuild.EmitOr(input, ibuild.EmitIntConst(mask & 0x7FFFFFFF));
|
||||
test = ibuild.EmitICmpUgt(test, ibuild.EmitIntConst(mask));
|
||||
|
||||
ibuild.EmitStoreCarry(test);
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, output);
|
||||
}
|
||||
|
||||
// count leading zeroes
|
||||
void JitILBase::cntlzwx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITIntegerOff);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||
val = ibuild.EmitCntlzw(val);
|
||||
ibuild.EmitStoreGReg(val, inst.RA);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
|
@ -1,310 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/JitILCommon/JitILBase.h"
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/HW/CPU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
void JitILBase::lhax(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoad16(addr);
|
||||
val = ibuild.EmitSExt16(val);
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
}
|
||||
|
||||
void JitILBase::lhaux(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoad16(addr);
|
||||
val = ibuild.EmitSExt16(val);
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
}
|
||||
|
||||
void JitILBase::lXz(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
if (inst.OPCD & 1)
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
|
||||
IREmitter::InstLoc val;
|
||||
|
||||
// Idle Skipping.
|
||||
// TODO: This really should be done somewhere else. Either lower in the IR
|
||||
// or higher in PPCAnalyst
|
||||
// TODO: We shouldn't use debug reads here.
|
||||
if (!CPU::IsStepping() && inst.OPCD == 32 && // Lwx
|
||||
(inst.hex & 0xFFFF0000) == 0x800D0000 &&
|
||||
(PowerPC::HostRead_U32(js.compilerPC + 4) == 0x28000000 ||
|
||||
(SConfig::GetInstance().bWii && PowerPC::HostRead_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
||||
PowerPC::HostRead_U32(js.compilerPC + 8) == 0x4182fff8)
|
||||
{
|
||||
val = ibuild.EmitLoad32(addr);
|
||||
ibuild.EmitIdleBranch(val, ibuild.EmitIntConst(js.compilerPC));
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (inst.OPCD & ~0x1)
|
||||
{
|
||||
case 32: // lwz
|
||||
val = ibuild.EmitLoad32(addr);
|
||||
break;
|
||||
case 40: // lhz
|
||||
val = ibuild.EmitLoad16(addr);
|
||||
break;
|
||||
case 34: // lbz
|
||||
val = ibuild.EmitLoad8(addr);
|
||||
break;
|
||||
default:
|
||||
PanicAlert("lXz: invalid access size");
|
||||
val = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
}
|
||||
|
||||
void JitILBase::lbzu(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
const IREmitter::InstLoc uAddress =
|
||||
ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), ibuild.EmitIntConst((int)inst.SIMM_16));
|
||||
const IREmitter::InstLoc temp = ibuild.EmitLoad8(uAddress);
|
||||
ibuild.EmitStoreGReg(temp, inst.RD);
|
||||
ibuild.EmitStoreGReg(uAddress, inst.RA);
|
||||
}
|
||||
|
||||
void JitILBase::lha(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst((s32)(s16)inst.SIMM_16);
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoad16(addr);
|
||||
val = ibuild.EmitSExt16(val);
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
}
|
||||
|
||||
void JitILBase::lhau(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst((s32)inst.SIMM_16);
|
||||
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoad16(addr);
|
||||
val = ibuild.EmitSExt16(val);
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
}
|
||||
|
||||
void JitILBase::lXzx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
|
||||
|
||||
if (inst.RA)
|
||||
{
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
if (inst.SUBOP10 & 32)
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
}
|
||||
|
||||
IREmitter::InstLoc val;
|
||||
switch (inst.SUBOP10 & ~32)
|
||||
{
|
||||
default:
|
||||
PanicAlert("lXzx: invalid access size");
|
||||
case 23: // lwzx
|
||||
val = ibuild.EmitLoad32(addr);
|
||||
break;
|
||||
case 279: // lhzx
|
||||
val = ibuild.EmitLoad16(addr);
|
||||
break;
|
||||
case 87: // lbzx
|
||||
val = ibuild.EmitLoad8(addr);
|
||||
break;
|
||||
}
|
||||
ibuild.EmitStoreGReg(val, inst.RD);
|
||||
}
|
||||
|
||||
void JitILBase::dcbst(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
|
||||
// If the dcbst instruction is preceded by dcbt, it is flushing a prefetched
|
||||
// memory location. Do not invalidate the JIT cache in this case as the memory
|
||||
// will be the same.
|
||||
// dcbt = 0x7c00022c
|
||||
// TODO: We shouldn't use a debug read here; it should be possible to get the
|
||||
// previous instruction from the JIT state.
|
||||
FALLBACK_IF((PowerPC::HostRead_U32(js.compilerPC - 4) & 0x7c00022c) != 0x7c00022c);
|
||||
}
|
||||
|
||||
// Zero cache line.
|
||||
void JitILBase::dcbz(UGeckoInstruction inst)
|
||||
{
|
||||
FALLBACK_IF(true);
|
||||
|
||||
// TODO!
|
||||
#if 0
|
||||
if (SConfig::GetInstance().bJITOff || SConfig::GetInstance().bJITLoadStoreOff)
|
||||
{
|
||||
Default(inst);
|
||||
return;
|
||||
}
|
||||
INSTRUCTION_START;
|
||||
MOV(32, R(RSCRATCH), gpr.R(inst.RB));
|
||||
if (inst.RA)
|
||||
ADD(32, R(RSCRATCH), gpr.R(inst.RA));
|
||||
AND(32, R(RSCRATCH), Imm32(~31));
|
||||
PXOR(XMM0, R(XMM0));
|
||||
MOVAPS(MComplex(RMEM, RSCRATCH, SCALE_1, 0), XMM0);
|
||||
MOVAPS(MComplex(RMEM, RSCRATCH, SCALE_1, 16), XMM0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void JitILBase::stX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
IREmitter::InstLoc value = ibuild.EmitLoadGReg(inst.RS);
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), addr);
|
||||
if (inst.OPCD & 1)
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
|
||||
switch (inst.OPCD & ~1)
|
||||
{
|
||||
case 36: // stw
|
||||
ibuild.EmitStore32(value, addr);
|
||||
break;
|
||||
case 44: // sth
|
||||
ibuild.EmitStore16(value, addr);
|
||||
break;
|
||||
case 38: // stb
|
||||
ibuild.EmitStore8(value, addr);
|
||||
break;
|
||||
default:
|
||||
_assert_msg_(DYNA_REC, 0, "stX: Invalid access size.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void JitILBase::stXx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
|
||||
IREmitter::InstLoc value = ibuild.EmitLoadGReg(inst.RS);
|
||||
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
if (inst.SUBOP10 & 32)
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
|
||||
switch (inst.SUBOP10 & ~32)
|
||||
{
|
||||
case 151: // stw
|
||||
ibuild.EmitStore32(value, addr);
|
||||
break;
|
||||
case 407: // sth
|
||||
ibuild.EmitStore16(value, addr);
|
||||
break;
|
||||
case 215: // stb
|
||||
ibuild.EmitStore8(value, addr);
|
||||
break;
|
||||
default:
|
||||
_assert_msg_(DYNA_REC, 0, "stXx: Invalid store size.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// A few games use these heavily in video codecs. (GFZP01 @ 0x80020E18)
|
||||
void JitILBase::lmw(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
for (int i = inst.RD; i < 32; i++)
|
||||
{
|
||||
IREmitter::InstLoc val = ibuild.EmitLoad32(addr);
|
||||
ibuild.EmitStoreGReg(val, i);
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitIntConst(4));
|
||||
}
|
||||
}
|
||||
|
||||
void JitILBase::stmw(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
for (int i = inst.RD; i < 32; i++)
|
||||
{
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(i);
|
||||
ibuild.EmitStore32(val, addr);
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitIntConst(4));
|
||||
}
|
||||
}
|
||||
|
||||
void JitILBase::icbi(UGeckoInstruction inst)
|
||||
{
|
||||
FallBackToInterpreter(inst);
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/JitILCommon/JitILBase.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
// TODO: Add peephole optimizations for multiple consecutive lfd/lfs/stfd/stfs since they are so
|
||||
// common,
|
||||
// and pshufb could help a lot.
|
||||
// Also add hacks for things like lfs/stfs the same reg consecutively, that is, simple memory moves.
|
||||
|
||||
void JitILBase::lfs(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitDupSingleToMReg(ibuild.EmitLoadSingle(addr));
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
void JitILBase::lfsu(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitDupSingleToMReg(ibuild.EmitLoadSingle(addr));
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
}
|
||||
|
||||
void JitILBase::lfd(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RD);
|
||||
val = ibuild.EmitInsertDoubleInMReg(ibuild.EmitLoadDouble(addr), val);
|
||||
ibuild.EmitStoreFReg(val, inst.RD);
|
||||
}
|
||||
|
||||
void JitILBase::lfdu(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FD);
|
||||
val = ibuild.EmitInsertDoubleInMReg(ibuild.EmitLoadDouble(addr), val);
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
}
|
||||
|
||||
void JitILBase::stfd(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RS);
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
if (inst.OPCD & 1)
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
|
||||
ibuild.EmitStoreDouble(val, addr);
|
||||
}
|
||||
|
||||
void JitILBase::stfs(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RS);
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
if (inst.OPCD & 1)
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
|
||||
val = ibuild.EmitDoubleToSingle(val);
|
||||
ibuild.EmitStoreSingle(val, addr);
|
||||
}
|
||||
|
||||
void JitILBase::stfsx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RS);
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
val = ibuild.EmitDoubleToSingle(val);
|
||||
ibuild.EmitStoreSingle(val, addr);
|
||||
}
|
||||
|
||||
void JitILBase::lfsx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStoreFloatingOff);
|
||||
FALLBACK_IF(jo.memcheck);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB), val;
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
val = ibuild.EmitDupSingleToMReg(ibuild.EmitLoadSingle(addr));
|
||||
ibuild.EmitStoreFReg(val, inst.RD);
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// 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)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStorePairedOff);
|
||||
FALLBACK_IF(jo.memcheck || inst.W);
|
||||
|
||||
// For performance, the AsmCommon routines assume address translation is on.
|
||||
FALLBACK_IF(!UReg_MSR(MSR).DR);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12);
|
||||
IREmitter::InstLoc val;
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
if (inst.OPCD == 61)
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
|
||||
val = ibuild.EmitLoadFReg(inst.RS);
|
||||
val = ibuild.EmitCompactMRegToPacked(val);
|
||||
ibuild.EmitStorePaired(val, addr, inst.I);
|
||||
}
|
||||
|
||||
void JitILBase::psq_l(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStorePairedOff);
|
||||
FALLBACK_IF(jo.memcheck || inst.W);
|
||||
|
||||
// For performance, the AsmCommon routines assume address translation is on.
|
||||
FALLBACK_IF(!UReg_MSR(MSR).DR);
|
||||
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12);
|
||||
IREmitter::InstLoc val;
|
||||
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
||||
if (inst.OPCD == 57)
|
||||
ibuild.EmitStoreGReg(addr, inst.RA);
|
||||
|
||||
val = ibuild.EmitLoadPaired(
|
||||
addr,
|
||||
inst.I | (inst.W << 3)); // The lower 3 bits is for GQR index. The next 1 bit is for inst.W
|
||||
val = ibuild.EmitExpandPackedToMReg(val);
|
||||
ibuild.EmitStoreFReg(val, inst.RD);
|
||||
}
|
|
@ -1,186 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/JitILCommon/JitILBase.h"
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
void JitILBase::ps_arith(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITPairedOff);
|
||||
FALLBACK_IF(inst.Rc || (inst.SUBOP5 != 21 && inst.SUBOP5 != 20 && inst.SUBOP5 != 25));
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
|
||||
IREmitter::InstLoc rhs;
|
||||
|
||||
if (inst.SUBOP5 == 25)
|
||||
rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||
else
|
||||
rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||
|
||||
val = ibuild.EmitCompactMRegToPacked(val);
|
||||
|
||||
switch (inst.SUBOP5)
|
||||
{
|
||||
case 20:
|
||||
val = ibuild.EmitFPSub(val, rhs);
|
||||
break;
|
||||
case 21:
|
||||
val = ibuild.EmitFPAdd(val, rhs);
|
||||
break;
|
||||
case 25:
|
||||
val = ibuild.EmitFPMul(val, rhs);
|
||||
}
|
||||
|
||||
val = ibuild.EmitExpandPackedToMReg(val);
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
void JitILBase::ps_sum(UGeckoInstruction inst)
|
||||
{
|
||||
// TODO: This operation strikes me as a bit strange...
|
||||
// perhaps we can optimize it depending on the users?
|
||||
// TODO: ps_sum breaks Sonic Colours (black screen)
|
||||
FALLBACK_IF(true);
|
||||
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITPairedOff);
|
||||
FALLBACK_IF(inst.Rc || inst.SUBOP5 != 10);
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
|
||||
IREmitter::InstLoc temp;
|
||||
|
||||
val = ibuild.EmitCompactMRegToPacked(val);
|
||||
val = ibuild.EmitFPDup0(val);
|
||||
temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||
val = ibuild.EmitFPAdd(val, temp);
|
||||
temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||
val = ibuild.EmitFPMerge11(val, temp);
|
||||
val = ibuild.EmitExpandPackedToMReg(val);
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
void JitILBase::ps_muls(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITPairedOff);
|
||||
FALLBACK_IF(inst.Rc);
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
|
||||
IREmitter::InstLoc rhs = ibuild.EmitLoadFReg(inst.FC);
|
||||
|
||||
val = ibuild.EmitCompactMRegToPacked(val);
|
||||
rhs = ibuild.EmitCompactMRegToPacked(rhs);
|
||||
|
||||
if (inst.SUBOP5 == 12)
|
||||
rhs = ibuild.EmitFPDup0(rhs);
|
||||
else
|
||||
rhs = ibuild.EmitFPDup1(rhs);
|
||||
|
||||
val = ibuild.EmitFPMul(val, rhs);
|
||||
val = ibuild.EmitExpandPackedToMReg(val);
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
// TODO: find easy cases and optimize them, do a breakout like ps_arith
|
||||
void JitILBase::ps_mergeXX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITPairedOff);
|
||||
FALLBACK_IF(inst.Rc);
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FA));
|
||||
IREmitter::InstLoc rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||
|
||||
switch (inst.SUBOP10)
|
||||
{
|
||||
case 528:
|
||||
val = ibuild.EmitFPMerge00(val, rhs);
|
||||
break; // 00
|
||||
case 560:
|
||||
val = ibuild.EmitFPMerge01(val, rhs);
|
||||
break; // 01
|
||||
case 592:
|
||||
val = ibuild.EmitFPMerge10(val, rhs);
|
||||
break; // 10
|
||||
case 624:
|
||||
val = ibuild.EmitFPMerge11(val, rhs);
|
||||
break; // 11
|
||||
default:
|
||||
_assert_msg_(DYNA_REC, 0, "ps_merge - invalid op");
|
||||
}
|
||||
|
||||
val = ibuild.EmitExpandPackedToMReg(val);
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
||||
|
||||
void JitILBase::ps_maddXX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITPairedOff);
|
||||
FALLBACK_IF(inst.Rc);
|
||||
|
||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), op2, op3;
|
||||
val = ibuild.EmitCompactMRegToPacked(val);
|
||||
|
||||
switch (inst.SUBOP5)
|
||||
{
|
||||
case 14: // madds0
|
||||
{
|
||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||
op2 = ibuild.EmitFPDup0(op2);
|
||||
val = ibuild.EmitFPMul(val, op2);
|
||||
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||
val = ibuild.EmitFPAdd(val, op3);
|
||||
break;
|
||||
}
|
||||
case 15: // madds1
|
||||
{
|
||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||
op2 = ibuild.EmitFPDup1(op2);
|
||||
val = ibuild.EmitFPMul(val, op2);
|
||||
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||
val = ibuild.EmitFPAdd(val, op3);
|
||||
break;
|
||||
}
|
||||
case 28: // msub
|
||||
{
|
||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||
val = ibuild.EmitFPMul(val, op2);
|
||||
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||
val = ibuild.EmitFPSub(val, op3);
|
||||
break;
|
||||
}
|
||||
case 29: // madd
|
||||
{
|
||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||
val = ibuild.EmitFPMul(val, op2);
|
||||
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||
val = ibuild.EmitFPAdd(val, op3);
|
||||
break;
|
||||
}
|
||||
case 30: // nmsub
|
||||
{
|
||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||
val = ibuild.EmitFPMul(val, op2);
|
||||
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||
val = ibuild.EmitFPSub(val, op3);
|
||||
val = ibuild.EmitFPNeg(val);
|
||||
break;
|
||||
}
|
||||
case 31: // nmadd
|
||||
{
|
||||
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||
val = ibuild.EmitFPMul(val, op2);
|
||||
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||
val = ibuild.EmitFPAdd(val, op3);
|
||||
val = ibuild.EmitFPNeg(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
val = ibuild.EmitExpandPackedToMReg(val);
|
||||
ibuild.EmitStoreFReg(val, inst.FD);
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/JitILCommon/JitILBase.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
void JitILBase::mtspr(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITSystemRegistersOff);
|
||||
u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F);
|
||||
|
||||
switch (iIndex)
|
||||
{
|
||||
case SPR_TL:
|
||||
case SPR_TU:
|
||||
FALLBACK_IF(true);
|
||||
case SPR_LR:
|
||||
ibuild.EmitStoreLink(ibuild.EmitLoadGReg(inst.RD));
|
||||
return;
|
||||
case SPR_CTR:
|
||||
ibuild.EmitStoreCTR(ibuild.EmitLoadGReg(inst.RD));
|
||||
return;
|
||||
case SPR_GQR0:
|
||||
case SPR_GQR0 + 1:
|
||||
case SPR_GQR0 + 2:
|
||||
case SPR_GQR0 + 3:
|
||||
case SPR_GQR0 + 4:
|
||||
case SPR_GQR0 + 5:
|
||||
case SPR_GQR0 + 6:
|
||||
case SPR_GQR0 + 7:
|
||||
ibuild.EmitStoreGQR(ibuild.EmitLoadGReg(inst.RD), iIndex - SPR_GQR0);
|
||||
return;
|
||||
case SPR_SRR0:
|
||||
case SPR_SRR1:
|
||||
ibuild.EmitStoreSRR(ibuild.EmitLoadGReg(inst.RD), iIndex - SPR_SRR0);
|
||||
return;
|
||||
default:
|
||||
FALLBACK_IF(true);
|
||||
}
|
||||
}
|
||||
|
||||
void JitILBase::mfspr(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITSystemRegistersOff);
|
||||
u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F);
|
||||
switch (iIndex)
|
||||
{
|
||||
case SPR_TL:
|
||||
case SPR_TU:
|
||||
FALLBACK_IF(true);
|
||||
case SPR_LR:
|
||||
ibuild.EmitStoreGReg(ibuild.EmitLoadLink(), inst.RD);
|
||||
return;
|
||||
case SPR_CTR:
|
||||
ibuild.EmitStoreGReg(ibuild.EmitLoadCTR(), inst.RD);
|
||||
return;
|
||||
case SPR_GQR0:
|
||||
case SPR_GQR0 + 1:
|
||||
case SPR_GQR0 + 2:
|
||||
case SPR_GQR0 + 3:
|
||||
case SPR_GQR0 + 4:
|
||||
case SPR_GQR0 + 5:
|
||||
case SPR_GQR0 + 6:
|
||||
case SPR_GQR0 + 7:
|
||||
ibuild.EmitStoreGReg(ibuild.EmitLoadGQR(iIndex - SPR_GQR0), inst.RD);
|
||||
return;
|
||||
default:
|
||||
FALLBACK_IF(true);
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// Don't interpret this, if we do we get thrown out
|
||||
// --------------
|
||||
void JitILBase::mtmsr(UGeckoInstruction inst)
|
||||
{
|
||||
ibuild.EmitStoreMSR(ibuild.EmitLoadGReg(inst.RS), ibuild.EmitIntConst(js.compilerPC));
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
}
|
||||
// ==============
|
||||
|
||||
void JitILBase::mfmsr(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITSystemRegistersOff);
|
||||
ibuild.EmitStoreGReg(ibuild.EmitLoadMSR(), inst.RD);
|
||||
}
|
||||
|
||||
void JitILBase::mftb(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START;
|
||||
JITDISABLE(bJITSystemRegistersOff);
|
||||
mfspr(inst);
|
||||
}
|
||||
|
||||
void JitILBase::mfcr(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START;
|
||||
JITDISABLE(bJITSystemRegistersOff);
|
||||
|
||||
IREmitter::InstLoc d = ibuild.EmitIntConst(0);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
IREmitter::InstLoc cr = ibuild.EmitLoadCR(i);
|
||||
cr = ibuild.EmitConvertFromFastCR(cr);
|
||||
cr = ibuild.EmitShl(cr, ibuild.EmitIntConst(28 - 4 * i));
|
||||
d = ibuild.EmitOr(d, cr);
|
||||
}
|
||||
ibuild.EmitStoreGReg(d, inst.RD);
|
||||
}
|
||||
|
||||
void JitILBase::mtcrf(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START;
|
||||
JITDISABLE(bJITSystemRegistersOff);
|
||||
|
||||
IREmitter::InstLoc s = ibuild.EmitLoadGReg(inst.RS);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (inst.CRM & (0x80 >> i))
|
||||
{
|
||||
IREmitter::InstLoc value;
|
||||
value = ibuild.EmitShrl(s, ibuild.EmitIntConst(28 - i * 4));
|
||||
value = ibuild.EmitAnd(value, ibuild.EmitIntConst(0xF));
|
||||
value = ibuild.EmitConvertToFastCR(value);
|
||||
ibuild.EmitStoreCR(value, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JitILBase::mcrf(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITSystemRegistersOff);
|
||||
|
||||
if (inst.CRFS != inst.CRFD)
|
||||
{
|
||||
ibuild.EmitStoreCR(ibuild.EmitLoadCR(inst.CRFS), inst.CRFD);
|
||||
}
|
||||
}
|
||||
|
||||
void JitILBase::crXX(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITSystemRegistersOff);
|
||||
|
||||
// Get bit CRBA in EAX aligned with bit CRBD
|
||||
const int shiftA = (inst.CRBD & 3) - (inst.CRBA & 3);
|
||||
IREmitter::InstLoc eax = ibuild.EmitLoadCR(inst.CRBA >> 2);
|
||||
eax = ibuild.EmitConvertFromFastCR(eax);
|
||||
if (shiftA < 0)
|
||||
eax = ibuild.EmitShl(eax, ibuild.EmitIntConst(-shiftA));
|
||||
else if (shiftA > 0)
|
||||
eax = ibuild.EmitShrl(eax, ibuild.EmitIntConst(shiftA));
|
||||
|
||||
// Get bit CRBB in ECX aligned with bit CRBD
|
||||
const int shiftB = (inst.CRBD & 3) - (inst.CRBB & 3);
|
||||
IREmitter::InstLoc ecx = ibuild.EmitLoadCR(inst.CRBB >> 2);
|
||||
ecx = ibuild.EmitConvertFromFastCR(ecx);
|
||||
if (shiftB < 0)
|
||||
ecx = ibuild.EmitShl(ecx, ibuild.EmitIntConst(-shiftB));
|
||||
else if (shiftB > 0)
|
||||
ecx = ibuild.EmitShrl(ecx, ibuild.EmitIntConst(shiftB));
|
||||
|
||||
// Compute combined bit
|
||||
const unsigned subop = inst.SUBOP10;
|
||||
switch (subop)
|
||||
{
|
||||
case 257: // crand
|
||||
eax = ibuild.EmitAnd(eax, ecx);
|
||||
break;
|
||||
case 129: // crandc
|
||||
ecx = ibuild.EmitNot(ecx);
|
||||
eax = ibuild.EmitAnd(eax, ecx);
|
||||
break;
|
||||
case 289: // creqv
|
||||
eax = ibuild.EmitXor(eax, ecx);
|
||||
eax = ibuild.EmitNot(eax);
|
||||
break;
|
||||
case 225: // crnand
|
||||
eax = ibuild.EmitAnd(eax, ecx);
|
||||
eax = ibuild.EmitNot(eax);
|
||||
break;
|
||||
case 33: // crnor
|
||||
eax = ibuild.EmitOr(eax, ecx);
|
||||
eax = ibuild.EmitNot(eax);
|
||||
break;
|
||||
case 449: // cror
|
||||
eax = ibuild.EmitOr(eax, ecx);
|
||||
break;
|
||||
case 417: // crorc
|
||||
ecx = ibuild.EmitNot(ecx);
|
||||
eax = ibuild.EmitOr(eax, ecx);
|
||||
break;
|
||||
case 193: // crxor
|
||||
eax = ibuild.EmitXor(eax, ecx);
|
||||
break;
|
||||
default:
|
||||
PanicAlert("crXX: invalid instruction");
|
||||
break;
|
||||
}
|
||||
|
||||
// Store result bit in CRBD
|
||||
eax = ibuild.EmitAnd(eax, ibuild.EmitIntConst(0x8 >> (inst.CRBD & 3)));
|
||||
IREmitter::InstLoc bd = ibuild.EmitLoadCR(inst.CRBD >> 2);
|
||||
bd = ibuild.EmitConvertFromFastCR(bd);
|
||||
bd = ibuild.EmitAnd(bd, ibuild.EmitIntConst(~(0x8 >> (inst.CRBD & 3))));
|
||||
bd = ibuild.EmitOr(bd, eax);
|
||||
bd = ibuild.EmitConvertToFastCR(bd);
|
||||
ibuild.EmitStoreCR(bd, inst.CRBD >> 2);
|
||||
}
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#if _M_X86
|
||||
#include "Core/PowerPC/Jit64/Jit.h"
|
||||
#include "Core/PowerPC/Jit64IL/JitIL.h"
|
||||
#endif
|
||||
|
||||
#if _M_ARM_64
|
||||
|
@ -53,9 +52,6 @@ CPUCoreBase* InitJitCore(int core)
|
|||
case PowerPC::CORE_JIT64:
|
||||
ptr = new Jit64();
|
||||
break;
|
||||
case PowerPC::CORE_JITIL64:
|
||||
ptr = new JitIL();
|
||||
break;
|
||||
#endif
|
||||
#if _M_ARM_64
|
||||
case PowerPC::CORE_JITARM64:
|
||||
|
|
|
@ -186,7 +186,7 @@ const std::vector<CPUCore>& AvailableCPUCores()
|
|||
static const std::vector<CPUCore> cpu_cores = {
|
||||
CORE_INTERPRETER, CORE_CACHEDINTERPRETER,
|
||||
#ifdef _M_X86_64
|
||||
CORE_JIT64, CORE_JITIL64,
|
||||
CORE_JIT64,
|
||||
#elif defined(_M_ARM_64)
|
||||
CORE_JITARM64,
|
||||
#endif
|
||||
|
|
|
@ -21,14 +21,14 @@ class PointerWrap;
|
|||
|
||||
namespace PowerPC
|
||||
{
|
||||
// The gaps in the CPUCore numbering are from cores that only existed in the past.
|
||||
// We avoid re-numbering cores so that settings will be compatible across versions.
|
||||
enum CPUCore
|
||||
{
|
||||
CORE_INTERPRETER,
|
||||
CORE_JIT64,
|
||||
CORE_JITIL64,
|
||||
CORE_JITARM,
|
||||
CORE_JITARM64,
|
||||
CORE_CACHEDINTERPRETER,
|
||||
CORE_INTERPRETER = 0,
|
||||
CORE_JIT64 = 1,
|
||||
CORE_JITARM64 = 4,
|
||||
CORE_CACHEDINTERPRETER = 5,
|
||||
};
|
||||
|
||||
enum class CoreMode
|
||||
|
|
|
@ -29,7 +29,6 @@ static const std::map<PowerPC::CPUCore, std::string> CPU_CORE_NAMES = {
|
|||
{PowerPC::CORE_INTERPRETER, _trans("Interpreter (slowest)")},
|
||||
{PowerPC::CORE_CACHEDINTERPRETER, _trans("Cached Interpreter (slower)")},
|
||||
{PowerPC::CORE_JIT64, _trans("JIT Recompiler (recommended)")},
|
||||
{PowerPC::CORE_JITIL64, _trans("JITIL Recompiler (slow, experimental)")},
|
||||
{PowerPC::CORE_JITARM64, _trans("JIT Arm64 (experimental)")},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue