Remove JITIL

This commit is contained in:
JosJuice 2017-05-19 16:57:31 +02:00
parent 1880a97bb0
commit 256a0cf4db
26 changed files with 9 additions and 7913 deletions

View file

@ -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

View file

@ -582,8 +582,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],

View file

@ -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;

View file

@ -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" />

View file

@ -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>

View file

@ -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;

View file

@ -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

View file

@ -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;
}

View file

@ -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);
};

View file

@ -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

View file

@ -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

View file

@ -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;
};

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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));
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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)")},
};