742 changes: 742 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.cpp

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Source/Core/Core/Src/PowerPC/JitArmIL/IR_Arm.h
@@ -0,0 +1 @@

365 changes: 365 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.cpp
@@ -0,0 +1,365 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.

#include <map>

#include "Common.h"
#include "../../HLE/HLE.h"
#include "../../Core.h"
#include "../../PatchEngine.h"
#include "../../CoreTiming.h"
#include "../../ConfigManager.h"
#include "../PowerPC.h"
#include "../Profiler.h"
#include "../PPCTables.h"
#include "../PPCAnalyst.h"
#include "../../HW/Memmap.h"
#include "../../HW/GPFifo.h"
#include "JitIL.h"
#include "JitIL_Tables.h"
#include "ArmEmitter.h"
#include "../JitInterface.h"

using namespace ArmGen;
using namespace PowerPC;

static int CODE_SIZE = 1024*1024*32;
namespace CPUCompare
{
extern u32 m_BlockStart;
}
void JitArmIL::Init()
{
AllocCodeSpace(CODE_SIZE);
blocks.Init();
asm_routines.Init();
}

void JitArmIL::ClearCache()
{
ClearCodeSpace();
blocks.Clear();
}

void JitArmIL::Shutdown()
{
FreeCodeSpace();
blocks.Shutdown();
asm_routines.Shutdown();
}
void JitArmIL::unknown_instruction(UGeckoInstruction inst)
{
// CCPU::Break();
PanicAlert("unknown_instruction %08x - Fix me ;)", inst.hex);
}

void JitArmIL::Default(UGeckoInstruction _inst)
{
ibuild.EmitInterpreterFallback(
ibuild.EmitIntConst(_inst.hex),
ibuild.EmitIntConst(js.compilerPC));
}

void JitArmIL::HLEFunction(UGeckoInstruction _inst)
{
// XXX
}

void JitArmIL::DoNothing(UGeckoInstruction _inst)
{
// Yup, just don't do anything.
}
void JitArmIL::Break(UGeckoInstruction _inst)
{
ibuild.EmitINT3();
}

void JitArmIL::DoDownCount()
{
ARMReg rA = R14;
ARMReg rB = R12;
MOVI2R(rA, (u32)&CoreTiming::downcount);
LDR(rB, rA);
if(js.downcountAmount < 255) // We can enlarge this if we used rotations
{
SUBS(rB, rB, js.downcountAmount);
STR(rB, rA);
}
else
{
ARMReg rC = R11;
MOVI2R(rC, js.downcountAmount);
SUBS(rB, rB, rC);
STR(rB, rA);
}
}

void JitArmIL::WriteExitDestInReg(ARMReg Reg)
{
STR(Reg, R9, PPCSTATE_OFF(pc));
DoDownCount();
MOVI2R(Reg, (u32)asm_routines.dispatcher);
B(Reg);
}

void JitArmIL::WriteRfiExitDestInR(ARMReg Reg)
{
STR(Reg, R9, PPCSTATE_OFF(pc));
DoDownCount();
MOVI2R(Reg, (u32)asm_routines.testExceptions);
B(Reg);
}
void JitArmIL::WriteExceptionExit()
{
DoDownCount();

MOVI2R(R14, (u32)asm_routines.testExceptions);
B(R14);
}
void JitArmIL::WriteExit(u32 destination, int exit_num)
{
DoDownCount();
//If nobody has taken care of this yet (this can be removed when all branches are done)
JitBlock *b = js.curBlock;
b->exitAddress[exit_num] = destination;
b->exitPtrs[exit_num] = GetWritableCodePtr();

// Link opportunity!
int block = blocks.GetBlockNumberFromStartAddress(destination);
if (block >= 0 && jo.enableBlocklink)
{
// It exists! Joy of joy!
B(blocks.GetBlock(block)->checkedEntry);
b->linkStatus[exit_num] = true;
}
else
{
MOVI2R(R14, destination);
STR(R14, R9, PPCSTATE_OFF(pc));
MOVI2R(R14, (u32)asm_routines.dispatcher);
B(R14);
}
}
void JitArmIL::PrintDebug(UGeckoInstruction inst, u32 level)
{
if (level > 0)
printf("Start: %08x OP '%s' Info\n", (u32)GetCodePtr(), PPCTables::GetInstructionName(inst));
if (level > 1)
{
GekkoOPInfo* Info = GetOpInfo(inst.hex);
printf("\tOuts\n");
if (Info->flags & FL_OUT_A)
printf("\t-OUT_A: %x\n", inst.RA);
if(Info->flags & FL_OUT_D)
printf("\t-OUT_D: %x\n", inst.RD);
printf("\tIns\n");
// A, AO, B, C, S
if(Info->flags & FL_IN_A)
printf("\t-IN_A: %x\n", inst.RA);
if(Info->flags & FL_IN_A0)
printf("\t-IN_A0: %x\n", inst.RA);
if(Info->flags & FL_IN_B)
printf("\t-IN_B: %x\n", inst.RB);
if(Info->flags & FL_IN_C)
printf("\t-IN_C: %x\n", inst.RC);
if(Info->flags & FL_IN_S)
printf("\t-IN_S: %x\n", inst.RS);
}
}

void STACKALIGN JitArmIL::Run()
{
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
pExecAddr();
}

void JitArmIL::SingleStep()
{
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
pExecAddr();
}
void STACKALIGN JitArmIL::Jit(u32 em_address)
{
if (GetSpaceLeft() < 0x10000 || blocks.IsFull() || Core::g_CoreStartupParameter.bJITNoBlockCache)
{
ClearCache();
}

int block_num = blocks.AllocateBlock(PowerPC::ppcState.pc);
JitBlock *b = blocks.GetBlock(block_num);
const u8* BlockPtr = DoJit(PowerPC::ppcState.pc, &code_buffer, b);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, BlockPtr);
}

const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b)
{
int blockSize = code_buf->GetSize();
// Memory exception on instruction fetch
bool memory_exception = false;

// A broken block is a block that does not end in a branch
bool broken_block = false;

if (Core::g_CoreStartupParameter.bEnableDebugging)
{
// Comment out the following to disable breakpoints (speed-up)
blockSize = 1;
broken_block = true;
}

if (em_address == 0)
{
Core::SetState(Core::CORE_PAUSE);
PanicAlert("ERROR: Compiling at 0. LR=%08x CTR=%08x", LR, CTR);
}

if (Core::g_CoreStartupParameter.bMMU && (em_address & JIT_ICACHE_VMEM_BIT))
{
if (!Memory::TranslateAddress(em_address, Memory::FLAG_OPCODE))
{
// Memory exception occurred during instruction fetch
memory_exception = true;
}
}


int size = 0;
js.isLastInstruction = false;
js.blockStart = em_address;
js.fifoBytesThisBlock = 0;
js.curBlock = b;
js.block_flags = 0;
js.cancel = false;

// 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 = em_address;
u32 merged_addresses[32];
const int capacity_of_merged_addresses = sizeof(merged_addresses) / sizeof(merged_addresses[0]);
int size_of_merged_addresses = 0;
if (!memory_exception)
{
// If there is a memory exception inside a block (broken_block==true), compile up to that instruction.
nextPC = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, broken_block, code_buf, blockSize, merged_addresses, capacity_of_merged_addresses, size_of_merged_addresses);
}
PPCAnalyst::CodeOp *ops = code_buf->codebuffer;

const u8 *start = GetCodePtr();
b->checkedEntry = start;
b->runCount = 0;

// Downcount flag check, Only valid for linked blocks
{
// XXX
}

const u8 *normalEntry = GetCodePtr();
b->normalEntry = normalEntry;

if (js.fpa.any)
{
// XXX
// This block uses FPU - needs to add FP exception bailout
}
js.rewriteStart = (u8*)GetCodePtr();

u64 codeHash = -1;
{
// For profiling and IR Writer
for (int i = 0; i < (int)size; i++)
{
const u64 inst = ops[i].inst.hex;
// Ported from boost::hash
codeHash ^= inst + (codeHash << 6) + (codeHash >> 2);
}
}

// Conditionally add profiling code.
if (Profiler::g_ProfileBlocks) {
// XXX
}
// Start up IR builder (structure that collects the
// instruction processed by the JIT routines)
ibuild.Reset();

js.downcountAmount = 0;
if (!Core::g_CoreStartupParameter.bEnableDebugging)
{
for (int i = 0; i < size_of_merged_addresses; ++i)
{
const u32 address = merged_addresses[i];
js.downcountAmount += PatchEngine::GetSpeedhackCycles(address);
}
}

js.skipnext = false;
js.blockSize = size;
js.compilerPC = nextPC;
// Translate instructions
for (int i = 0; i < (int)size; i++)
{
js.compilerPC = ops[i].address;
js.op = &ops[i];
js.instructionNumber = i;
const GekkoOPInfo *opinfo = ops[i].opinfo;
js.downcountAmount += (opinfo->numCyclesMinusOne + 1);

if (i == (int)size - 1)
{
// WARNING - cmp->branch merging will screw this up.
js.isLastInstruction = true;
js.next_inst = 0;
if (Profiler::g_ProfileBlocks) {
// CAUTION!!! push on stack regs you use, do your stuff, then pop
PROFILER_VPUSH;
// get end tic
PROFILER_QUERY_PERFORMANCE_COUNTER(&b->ticStop);
// tic counter += (end tic - start tic)
PROFILER_ADD_DIFF_LARGE_INTEGER(&b->ticCounter, &b->ticStop, &b->ticStart);
PROFILER_VPOP;
}
}
else
{
// help peephole optimizations
js.next_inst = ops[i + 1].inst;
js.next_compilerPC = ops[i + 1].address;
}
if (!ops[i].skip)
{
PrintDebug(ops[i].inst, 0);
if (js.memcheck && (opinfo->flags & FL_USE_FPU))
{
// Don't do this yet
BKPT(0x7777);
}
JitArmILTables::CompileInstruction(ops[i]);
if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
{
// Don't do this yet
BKPT(0x666);
}
}
}
if (memory_exception)
BKPT(0x500);
if (broken_block)
{
printf("Broken Block going to 0x%08x\n", nextPC);
WriteExit(nextPC, 0);
}

// Perform actual code generation

WriteCode();
b->flags = js.block_flags;
b->codeSize = (u32)(GetCodePtr() - normalEntry);
b->originalSize = size;

{
}
FlushIcache();
return start;

}
99 changes: 99 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArmIL/JitIL.h
@@ -0,0 +1,99 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.

#ifndef _JITARMIL_H
#define _JITARMIL_H

#include "../PPCAnalyst.h"
#include "ArmEmitter.h"
#include "../JitArm32/JitArmCache.h"
#include "../JitILCommon/JitILBase.h"
#include "../JitILCommon/IR.h"
#include "../JitCommon/JitBase.h"
#include "JitILAsm.h"

#define JITDISABLE(setting) \
if (Core::g_CoreStartupParameter.bJITOff || \
Core::g_CoreStartupParameter.setting) \
{Default(inst); return;}

#define PPCSTATE_OFF(elem) ((s32)STRUCT_OFF(PowerPC::ppcState, elem) - (s32)STRUCT_OFF(PowerPC::ppcState, spr[0]))
class JitArmIL : public JitILBase, public ArmGen::ARMXCodeBlock
{
private:
JitArmBlockCache blocks;
JitArmILAsmRoutineManager asm_routines;

void PrintDebug(UGeckoInstruction inst, u32 level);
void DoDownCount();

public:
// Initialization, etc
JitArmIL() {}
~JitArmIL() {}

void Init();
void Shutdown();

// Jit!

void Jit(u32 em_address);
const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b);

JitBaseBlockCache *GetBlockCache() { return &blocks; }

const u8 *BackPatch(u8 *codePtr, u32 em_address, void *ctx) { return NULL; }

bool IsInCodeSpace(u8 *ptr) { return IsInSpace(ptr); }

void ClearCache();
const u8 *GetDispatcher() {
return asm_routines.dispatcher; // asm_routines.dispatcher
}
const CommonAsmRoutinesBase *GetAsmRoutines() {
return &asm_routines;
}

const char *GetName() {
return "JITARMIL";
}

// Run!

void Run();
void SingleStep();
//
void WriteCode();
void WriteExit(u32 destination, int exit_num);
void WriteExitDestInReg(ARMReg Reg);
void WriteRfiExitDestInR(ARMReg Reg);
void WriteExceptionExit();

// OPCODES
void unknown_instruction(UGeckoInstruction inst);
void Default(UGeckoInstruction inst);
void DoNothing(UGeckoInstruction inst);
void HLEFunction(UGeckoInstruction inst);
void Break(UGeckoInstruction inst);

void DynaRunTable4(UGeckoInstruction inst);
void DynaRunTable19(UGeckoInstruction inst);
void DynaRunTable31(UGeckoInstruction inst);
void DynaRunTable59(UGeckoInstruction inst);
void DynaRunTable63(UGeckoInstruction inst);

// Binary ops
void BIN_AND(ARMReg reg, Operand2 op2);
void BIN_XOR(ARMReg reg, Operand2 op2);
void BIN_OR(ARMReg reg, Operand2 op2);
void BIN_ADD(ARMReg reg, Operand2 op2);

// Branches
void bx(UGeckoInstruction inst);
void bcx(UGeckoInstruction inst);
void bclrx(UGeckoInstruction inst);
void bcctrx(UGeckoInstruction inst);
};

#endif
121 changes: 121 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArmIL/JitILAsm.cpp
@@ -0,0 +1,121 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "../../HW/Memmap.h"

#include "../PowerPC.h"
#include "../../CoreTiming.h"
#include "MemoryUtil.h"

#include "JitIL.h"
#include "../JitCommon/JitCache.h"

#include "../../HW/GPFifo.h"
#include "../../Core.h"

#include "JitILAsm.h"
#include "ArmEmitter.h"

JitArmILAsmRoutineManager armil_asm_routines;
void JitArmILAsmRoutineManager::Generate()
{
enterCode = GetCodePtr();
PUSH(9, R4, R5, R6, R7, R8, R9, R10, R11, _LR);
// Take care to 8-byte align stack for function calls.
// We are misaligned here because of an odd number of args for PUSH.
// It's not like x86 where you need to account for an extra 4 bytes
// consumed by CALL.
SUB(_SP, _SP, 4);

MOVI2R(R0, (u32)&CoreTiming::downcount);
MOVI2R(R9, (u32)&PowerPC::ppcState.spr[0]);

FixupBranch skipToRealDispatcher = B();
dispatcher = GetCodePtr();
printf("ILDispatcher is %p\n", dispatcher);

// Downcount Check
// The result of slice decrementation should be in flags if somebody jumped here
// IMPORTANT - We jump on negative, not carry!!!
FixupBranch bail = B_CC(CC_MI);

SetJumpTarget(skipToRealDispatcher);
dispatcherNoCheck = GetCodePtr();

// This block of code gets the address of the compiled block of code
// It runs though to the compiling portion if it isn't found
LDR(R12, R9, PPCSTATE_OFF(pc));// Load the current PC into R12

Operand2 iCacheMask = Operand2(0xE, 2); // JIT_ICACHE_MASK
BIC(R12, R12, iCacheMask); // R12 contains PC & JIT_ICACHE_MASK here.

MOVI2R(R14, (u32)jit->GetBlockCache()->GetICache());

LDR(R12, R14, R12); // R12 contains iCache[PC & JIT_ICACHE_MASK] here
// R12 Confirmed this is the correct iCache Location loaded.
TST(R12, 0xFC); // Test to see if it is a JIT block.

SetCC(CC_EQ);
// Success, it is our Jitblock.
MOVI2R(R14, (u32)jit->GetBlockCache()->GetCodePointers());
// LDR R14 right here to get CodePointers()[0] pointer.
REV(R12, R12); // Reversing this gives us our JITblock.
LSL(R12, R12, 2); // Multiply by four because address locations are u32 in size
LDR(R14, R14, R12); // Load the block address in to R14

B(R14);
// No need to jump anywhere after here, the block will go back to dispatcher start
SetCC();

// If we get to this point, that means that we don't have the block cached to execute
// So call ArmJit to compile the block and then execute it.
MOVI2R(R14, (u32)&Jit);
BL(R14);

B(dispatcherNoCheck);

// fpException()
// Floating Point Exception Check, Jumped to if false
fpException = GetCodePtr();
LDR(R0, R9, PPCSTATE_OFF(Exceptions));
ORR(R0, R0, EXCEPTION_FPU_UNAVAILABLE);
STR(R0, R9, PPCSTATE_OFF(Exceptions));
QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions);
LDR(R0, R9, PPCSTATE_OFF(npc));
STR(R0, R9, PPCSTATE_OFF(pc));
B(dispatcher);

SetJumpTarget(bail);
doTiming = GetCodePtr();
// XXX: In JIT64, Advance() gets called /after/ the exception checking
// once it jumps back to the start of outerLoop
QuickCallFunction(R14, (void*)&CoreTiming::Advance);

// Does exception checking
testExceptions = GetCodePtr();
LDR(R0, R9, PPCSTATE_OFF(pc));
STR(R0, R9, PPCSTATE_OFF(npc));
QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions);
LDR(R0, R9, PPCSTATE_OFF(npc));
STR(R0, R9, PPCSTATE_OFF(pc));
// Check the state pointer to see if we are exiting
// Gets checked on every exception check
MOVI2R(R0, (u32)PowerPC::GetStatePtr());
MVN(R1, 0);
LDR(R0, R0);
TST(R0, R1);
FixupBranch Exit = B_CC(CC_NEQ);

B(dispatcher);

SetJumpTarget(Exit);

ADD(_SP, _SP, 4);

POP(9, R4, R5, R6, R7, R8, R9, R10, R11, _PC); // Returns

GenerateCommon();

FlushIcache();
}

32 changes: 32 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArmIL/JitILAsm.h
@@ -0,0 +1,32 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.

#ifndef _JITARMILASM_H
#define _JITARMILASM_H
#include "ArmEmitter.h"
#include "../JitCommon/JitAsmCommon.h"
using namespace ArmGen;
class JitArmILAsmRoutineManager : public CommonAsmRoutinesBase, public ARMXCodeBlock
{
private:
void Generate();
void GenerateCommon() {}

public:
void Init() {
AllocCodeSpace(8192);
Generate();
WriteProtect();
}

void Shutdown() {
FreeCodeSpace();
}
};

extern JitArmILAsmRoutineManager armil_asm_routines;

#endif


Expand Up @@ -6,44 +6,18 @@

#include "../../ConfigManager.h"
#include "../PowerPC.h"
#include "../../CoreTiming.h"
#include "../PPCTables.h"
#include "x64Emitter.h"

#include "JitIL.h"
#include "JitILAsm.h"

#include "../../HW/Memmap.h"

// The branches are known good, or at least reasonably good.
// No need for a disable-mechanism.
#define NORMALBRANCH_START Default(inst); ibuild.EmitInterpreterBranch(); return;
//#define NORMALBRANCH_START

// 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 Default(inst); ibuild.EmitInterpreterBranch(); return;
#define NORMALBRANCH_START

using namespace Gen;

void JitIL::sc(UGeckoInstruction inst)
{
ibuild.EmitSystemCall(ibuild.EmitIntConst(js.compilerPC));
}

void JitIL::rfi(UGeckoInstruction inst)
void JitArmIL::bx(UGeckoInstruction inst)
{
ibuild.EmitRFIExit();
}

void JitIL::bx(UGeckoInstruction inst)
{
NORMALBRANCH_START
//NORMALBRANCH_START
INSTRUCTION_START;

// We must always process the following sentence
Expand Down Expand Up @@ -71,7 +45,6 @@ void JitIL::bx(UGeckoInstruction inst)

ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination));
}

static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst) {
IREmitter::InstLoc CRTest = 0, CTRTest = 0;
if ((inst.BO & 16) == 0) // Test a CR bit
Expand Down Expand Up @@ -109,7 +82,32 @@ static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruc
return Test;
}

void JitIL::bcx(UGeckoInstruction inst)
void JitArmIL::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);
}
void JitArmIL::bcx(UGeckoInstruction inst)
{
NORMALBRANCH_START
if (inst.LK)
Expand Down Expand Up @@ -140,7 +138,7 @@ void JitIL::bcx(UGeckoInstruction inst)
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
}

void JitIL::bcctrx(UGeckoInstruction inst)
void JitArmIL::bcctrx(UGeckoInstruction inst)
{
NORMALBRANCH_START
if ((inst.BO & 4) == 0) {
Expand Down Expand Up @@ -169,28 +167,3 @@ void JitIL::bcctrx(UGeckoInstruction inst)
ibuild.EmitBranchUncond(destination);
}

void JitIL::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);
}
489 changes: 489 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.cpp

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArmIL/JitIL_Tables.h
@@ -0,0 +1,16 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.

#ifndef JITARMIL_TABLES_H
#define JITARMIL_TABLES_H

#include "../Gekko.h"
#include "../PPCTables.h"

namespace JitArmILTables
{
void CompileInstruction(PPCAnalyst::CodeOp & op);
void InitTables();
}
#endif
14 changes: 14 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitCommon/JitBackpatch.h
Expand Up @@ -107,6 +107,19 @@
#define CTX_R15 gregs[REG_R15]
#define CTX_RIP gregs[REG_RIP]
#elif defined(_M_IX86)
#ifdef ANDROID
#include <asm/sigcontext.h>
typedef sigcontext SContext;
#define CTX_EAX eax
#define CTX_EBX ebx
#define CTX_ECX ecx
#define CTX_EDX edx
#define CTX_EDI edi
#define CTX_ESI esi
#define CTX_EBP ebp
#define CTX_ESP esp
#define CTX_EIP eip
#else
#include <ucontext.h>
typedef mcontext_t SContext;
#define CTX_EAX gregs[REG_EAX]
Expand All @@ -118,6 +131,7 @@
#define CTX_EBP gregs[REG_EBP]
#define CTX_ESP gregs[REG_ESP]
#define CTX_EIP gregs[REG_EIP]
#endif
#elif defined(_M_ARM)
// Add others if required.
typedef struct sigcontext SContext;
Expand Down
Expand Up @@ -124,8 +124,6 @@ Fix profiled loads/stores to work safely. On 32-bit, one solution is to
#include "../PPCTables.h"
#include "../../CoreTiming.h"
#include "../../HW/Memmap.h"
#include "JitILAsm.h"
#include "JitIL.h"
#include "../../HW/GPFifo.h"
#include "../../Core.h"
using namespace Gen;
Expand Down
File renamed without changes.
146 changes: 146 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitILCommon/JitILBase.h
@@ -0,0 +1,146 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.

#ifndef _JITILBASE_H
#define _JITILBASE_H

#include "../PPCAnalyst.h"
#include "IR.h"
#include "../JitCommon/JitBase.h"

#define INSTRUCTION_START

#define JITDISABLE(setting) \
if (Core::g_CoreStartupParameter.bJITOff || \
Core::g_CoreStartupParameter.setting) \
{Default(inst); return;}

class JitILBase : public JitBase
{
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;
public:
JitILBase() : code_buffer(32000) {}
~JitILBase() {}

IREmitter::IRBuilder ibuild;

virtual JitBaseBlockCache *GetBlockCache() = 0;

virtual void Jit(u32 em_address) = 0;

virtual const u8 *BackPatch(u8 *codePtr, u32 em_address, void *ctx) = 0;

virtual const CommonAsmRoutinesBase *GetAsmRoutines() = 0;

virtual bool IsInCodeSpace(u8 *ptr) = 0;

// OPCODES
virtual void unknown_instruction(UGeckoInstruction inst) = 0;
virtual void Default(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 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);

// 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_sel(UGeckoInstruction inst);
void ps_mr(UGeckoInstruction inst);
void ps_sign(UGeckoInstruction inst); //aggregate
void ps_arith(UGeckoInstruction inst); //aggregate
void ps_mergeXX(UGeckoInstruction inst);
void ps_maddXX(UGeckoInstruction inst);
void ps_rsqrte(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 lfd(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);

};
#endif
191 changes: 191 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitILCommon/JitILBase_Branch.cpp
@@ -0,0 +1,191 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.

#include "Common.h"

#include "../../ConfigManager.h"
#include "../PowerPC.h"
#include "../../CoreTiming.h"
#include "../PPCTables.h"
#include "JitILBase.h"

#include "../../HW/Memmap.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 Default(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 TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst) {
IREmitter::InstLoc CRTest = 0, CTRTest = 0;
if ((inst.BO & 16) == 0) // Test a CR bit
{
IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2);
IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3));
CRTest = ibuild.EmitAnd(CRReg, CRCmp);
if (!(inst.BO & 8))
CRTest = ibuild.EmitXor(CRCmp, CRTest);
}

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

if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle &&
inst.hex == 0x4182fff8 &&
(Memory::ReadUnchecked_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 &&
(Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x28000000 ||
(SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x2C000000))
)
{
ibuild.EmitIdleBranch(Test, ibuild.EmitIntConst(destination));
}
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
{
IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2);
IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3));
test = ibuild.EmitAnd(CRReg, CRCmp);
if (!(inst.BO & 8))
test = ibuild.EmitXor(test, CRCmp);
} 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);
}
Expand Up @@ -7,14 +7,10 @@
#include "../../Core.h"
#include "../PowerPC.h"
#include "../PPCTables.h"
#include "x64Emitter.h"

#include "JitIL.h"
#include "JitILBase.h"

//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START

void JitIL::fp_arith_s(UGeckoInstruction inst)
void JitILBase::fp_arith_s(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITFloatingPointOff)
Expand Down Expand Up @@ -57,7 +53,7 @@ void JitIL::fp_arith_s(UGeckoInstruction inst)
ibuild.EmitStoreFReg(val, inst.FD);
}

void JitIL::fmaddXX(UGeckoInstruction inst)
void JitILBase::fmaddXX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITFloatingPointOff)
Expand Down Expand Up @@ -85,7 +81,7 @@ void JitIL::fmaddXX(UGeckoInstruction inst)
ibuild.EmitStoreFReg(val, inst.FD);
}

void JitIL::fmrx(UGeckoInstruction inst)
void JitILBase::fmrx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITFloatingPointOff)
Expand All @@ -97,7 +93,7 @@ void JitIL::fmrx(UGeckoInstruction inst)
ibuild.EmitStoreFReg(val, inst.FD);
}

void JitIL::fcmpx(UGeckoInstruction inst)
void JitILBase::fcmpx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITFloatingPointOff)
Expand All @@ -110,7 +106,7 @@ void JitIL::fcmpx(UGeckoInstruction inst)
ibuild.EmitStoreCR(res, inst.CRFD);
}

void JitIL::fsign(UGeckoInstruction inst)
void JitILBase::fsign(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITFloatingPointOff)
Expand Down
Expand Up @@ -9,13 +9,8 @@
#include "../../Core.h" // include "Common.h", "CoreParameter.h", SCoreStartupParameter
#include "../PowerPC.h"
#include "../PPCTables.h"
#include "x64Emitter.h"

#include "JitIL.h"
#include "JitILAsm.h"

//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START
#include "JitILBase.h"

static void ComputeRC(IREmitter::IRBuilder& ibuild,
IREmitter::InstLoc val) {
Expand All @@ -24,7 +19,7 @@ static void ComputeRC(IREmitter::IRBuilder& ibuild,
ibuild.EmitStoreCR(res, 0);
}

void JitIL::reg_imm(UGeckoInstruction inst)
void JitILBase::reg_imm(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand Down Expand Up @@ -92,7 +87,7 @@ void JitIL::reg_imm(UGeckoInstruction inst)
}
}

void JitIL::cmpXX(UGeckoInstruction inst)
void JitILBase::cmpXX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -117,7 +112,7 @@ void JitIL::cmpXX(UGeckoInstruction inst)
ibuild.EmitStoreCR(res, inst.CRFD);
}

void JitIL::boolX(UGeckoInstruction inst)
void JitILBase::boolX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand Down Expand Up @@ -170,7 +165,7 @@ void JitIL::boolX(UGeckoInstruction inst)
ComputeRC(ibuild, a);
}

void JitIL::extsbx(UGeckoInstruction inst)
void JitILBase::extsbx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -181,7 +176,7 @@ void JitIL::extsbx(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::extshx(UGeckoInstruction inst)
void JitILBase::extshx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -192,7 +187,7 @@ void JitIL::extshx(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::subfic(UGeckoInstruction inst)
void JitILBase::subfic(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -211,7 +206,7 @@ void JitIL::subfic(UGeckoInstruction inst)
ibuild.EmitStoreCarry(test);
}

void JitIL::subfcx(UGeckoInstruction inst)
void JitILBase::subfcx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -228,7 +223,7 @@ void JitIL::subfcx(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::subfex(UGeckoInstruction inst)
void JitILBase::subfex(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -249,7 +244,7 @@ void JitIL::subfex(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::subfx(UGeckoInstruction inst)
void JitILBase::subfx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -261,7 +256,7 @@ void JitIL::subfx(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::mulli(UGeckoInstruction inst)
void JitILBase::mulli(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -270,7 +265,7 @@ void JitIL::mulli(UGeckoInstruction inst)
ibuild.EmitStoreGReg(val, inst.RD);
}

void JitIL::mullwx(UGeckoInstruction inst)
void JitILBase::mullwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -281,7 +276,7 @@ void JitIL::mullwx(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::mulhwux(UGeckoInstruction inst)
void JitILBase::mulhwux(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -295,7 +290,7 @@ void JitIL::mulhwux(UGeckoInstruction inst)
}

// skipped some of the special handling in here - if we get crashes, let the interpreter handle this op
void JitIL::divwux(UGeckoInstruction inst) {
void JitILBase::divwux(UGeckoInstruction inst) {
Default(inst); return;
#if 0
int a = inst.RA, b = inst.RB, d = inst.RD;
Expand All @@ -319,7 +314,7 @@ void JitIL::divwux(UGeckoInstruction inst) {
#endif
}

void JitIL::addx(UGeckoInstruction inst)
void JitILBase::addx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -330,7 +325,7 @@ void JitIL::addx(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::addzex(UGeckoInstruction inst)
void JitILBase::addzex(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -344,7 +339,7 @@ void JitIL::addzex(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::addex(UGeckoInstruction inst)
void JitILBase::addex(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -367,7 +362,7 @@ void JitIL::addex(UGeckoInstruction inst)
ComputeRC(ibuild, abc);
}

void JitIL::rlwinmx(UGeckoInstruction inst)
void JitILBase::rlwinmx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -381,7 +376,7 @@ void JitIL::rlwinmx(UGeckoInstruction inst)
}


void JitIL::rlwimix(UGeckoInstruction inst)
void JitILBase::rlwimix(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -397,7 +392,7 @@ void JitIL::rlwimix(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::rlwnmx(UGeckoInstruction inst)
void JitILBase::rlwnmx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -410,7 +405,7 @@ void JitIL::rlwnmx(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::negx(UGeckoInstruction inst)
void JitILBase::negx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -421,7 +416,7 @@ void JitIL::negx(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::srwx(UGeckoInstruction inst)
void JitILBase::srwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -440,7 +435,7 @@ void JitIL::srwx(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::slwx(UGeckoInstruction inst)
void JitILBase::slwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -459,7 +454,7 @@ void JitIL::slwx(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::srawx(UGeckoInstruction inst)
void JitILBase::srawx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -485,7 +480,7 @@ void JitIL::srawx(UGeckoInstruction inst)
ComputeRC(ibuild, val);
}

void JitIL::srawix(UGeckoInstruction inst)
void JitILBase::srawix(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand All @@ -502,7 +497,7 @@ void JitIL::srawix(UGeckoInstruction inst)
}

// count leading zeroes
void JitIL::cntlzwx(UGeckoInstruction inst)
void JitILBase::cntlzwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff)
Expand Down
Expand Up @@ -2,26 +2,17 @@
// Licensed under GPLv2
// Refer to the license.txt file included.

// TODO(ector): Tons of pshufb optimization of the loads/stores, for SSSE3+, possibly SSE4, only.
// Should give a very noticable speed boost to paired single heavy code.

#include "Common.h"

#include "../PowerPC.h"
#include "../../Core.h"
#include "../../HW/GPFifo.h"
#include "../../HW/Memmap.h"
#include "../PPCTables.h"
#include "x64Emitter.h"
#include "x64ABI.h"

#include "JitIL.h"
#include "JitILAsm.h"

//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START
#include "JitILBase.h"

void JitIL::lhax(UGeckoInstruction inst)
void JitILBase::lhax(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreOff)
Expand All @@ -34,7 +25,7 @@ void JitIL::lhax(UGeckoInstruction inst)
ibuild.EmitStoreGReg(val, inst.RD);
}

void JitIL::lXz(UGeckoInstruction inst)
void JitILBase::lXz(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreOff)
Expand All @@ -55,7 +46,7 @@ void JitIL::lXz(UGeckoInstruction inst)
ibuild.EmitStoreGReg(val, inst.RD);
}

void JitIL::lbzu(UGeckoInstruction inst) {
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));
Expand All @@ -64,7 +55,7 @@ void JitIL::lbzu(UGeckoInstruction inst) {
ibuild.EmitStoreGReg(uAddress, inst.RA);
}

void JitIL::lha(UGeckoInstruction inst)
void JitILBase::lha(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreOff)
Expand All @@ -78,7 +69,7 @@ void JitIL::lha(UGeckoInstruction inst)
ibuild.EmitStoreGReg(val, inst.RD);
}

void JitIL::lXzx(UGeckoInstruction inst)
void JitILBase::lXzx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreOff)
Expand All @@ -100,7 +91,7 @@ void JitIL::lXzx(UGeckoInstruction inst)
ibuild.EmitStoreGReg(val, inst.RD);
}

void JitIL::dcbst(UGeckoInstruction inst)
void JitILBase::dcbst(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreOff)
Expand All @@ -116,7 +107,7 @@ void JitIL::dcbst(UGeckoInstruction inst)
}

// Zero cache line.
void JitIL::dcbz(UGeckoInstruction inst)
void JitILBase::dcbz(UGeckoInstruction inst)
{
Default(inst); return;

Expand All @@ -141,7 +132,7 @@ void JitIL::dcbz(UGeckoInstruction inst)
#endif
}

void JitIL::stX(UGeckoInstruction inst)
void JitILBase::stX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreOff)
Expand All @@ -161,7 +152,7 @@ void JitIL::stX(UGeckoInstruction inst)
}
}

void JitIL::stXx(UGeckoInstruction inst)
void JitILBase::stXx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreOff)
Expand All @@ -181,7 +172,7 @@ void JitIL::stXx(UGeckoInstruction inst)
}

// A few games use these heavily in video codecs. (GFZP01 @ 0x80020E18)
void JitIL::lmw(UGeckoInstruction inst)
void JitILBase::lmw(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreOff)
Expand All @@ -197,7 +188,7 @@ void JitIL::lmw(UGeckoInstruction inst)
}
}

void JitIL::stmw(UGeckoInstruction inst)
void JitILBase::stmw(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreOff)
Expand All @@ -213,7 +204,7 @@ void JitIL::stmw(UGeckoInstruction inst)
}
}

void JitIL::icbi(UGeckoInstruction inst)
void JitILBase::icbi(UGeckoInstruction inst)
{
Default(inst);
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
Expand Down
Expand Up @@ -2,31 +2,21 @@
// Licensed under GPLv2
// Refer to the license.txt file included.

// TODO(ector): Tons of pshufb optimization of the loads/stores, for SSSE3+, possibly SSE4, only.
// Should give a very noticable speed boost to paired single heavy code.

#include "Common.h"

#include "../PowerPC.h"
#include "../../Core.h" // include "Common.h", "CoreParameter.h"
#include "../../HW/GPFifo.h"
#include "../../HW/Memmap.h"
#include "../PPCTables.h"
#include "CPUDetect.h"
#include "x64Emitter.h"
#include "x64ABI.h"

#include "JitIL.h"
#include "JitILAsm.h"

//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START
#include "JitILBase.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 JitIL::lfs(UGeckoInstruction inst)
void JitILBase::lfs(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreFloatingOff)
Expand All @@ -40,7 +30,7 @@ void JitIL::lfs(UGeckoInstruction inst)
}


void JitIL::lfd(UGeckoInstruction inst)
void JitILBase::lfd(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreFloatingOff)
Expand All @@ -55,7 +45,7 @@ void JitIL::lfd(UGeckoInstruction inst)
}


void JitIL::stfd(UGeckoInstruction inst)
void JitILBase::stfd(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreFloatingOff)
Expand All @@ -71,7 +61,7 @@ void JitIL::stfd(UGeckoInstruction inst)
}


void JitIL::stfs(UGeckoInstruction inst)
void JitILBase::stfs(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreFloatingOff)
Expand All @@ -88,7 +78,7 @@ void JitIL::stfs(UGeckoInstruction inst)
}


void JitIL::stfsx(UGeckoInstruction inst)
void JitILBase::stfsx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreFloatingOff)
Expand All @@ -103,7 +93,7 @@ void JitIL::stfsx(UGeckoInstruction inst)
}


void JitIL::lfsx(UGeckoInstruction inst)
void JitILBase::lfsx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStoreFloatingOff)
Expand Down
Expand Up @@ -9,17 +9,10 @@
#include "../../HW/GPFifo.h"
#include "../../HW/Memmap.h"
#include "../PPCTables.h"
#include "CPUDetect.h"
#include "x64Emitter.h"
#include "x64ABI.h"

#include "JitIL.h"
#include "JitILAsm.h"
#include "JitILBase.h"

//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START

void JitIL::psq_st(UGeckoInstruction inst)
void JitILBase::psq_st(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStorePairedOff)
Expand All @@ -35,7 +28,7 @@ void JitIL::psq_st(UGeckoInstruction inst)
ibuild.EmitStorePaired(val, addr, inst.I);
}

void JitIL::psq_l(UGeckoInstruction inst)
void JitILBase::psq_l(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITLoadStorePairedOff)
Expand Down
Expand Up @@ -7,32 +7,31 @@
#include "../../Core.h"
#include "../PowerPC.h"
#include "../PPCTables.h"
#include "x64Emitter.h"
#include "../../HW/GPFifo.h"

#include "JitIL.h"
#include "JitILBase.h"

void JitIL::ps_mr(UGeckoInstruction inst)
void JitILBase::ps_mr(UGeckoInstruction inst)
{
Default(inst); return;
}

void JitIL::ps_sel(UGeckoInstruction inst)
void JitILBase::ps_sel(UGeckoInstruction inst)
{
Default(inst); return;
}

void JitIL::ps_sign(UGeckoInstruction inst)
void JitILBase::ps_sign(UGeckoInstruction inst)
{
Default(inst); return;
}

void JitIL::ps_rsqrte(UGeckoInstruction inst)
void JitILBase::ps_rsqrte(UGeckoInstruction inst)
{
Default(inst); return;
}

void JitIL::ps_arith(UGeckoInstruction inst)
void JitILBase::ps_arith(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITPairedOff)
Expand Down Expand Up @@ -61,7 +60,7 @@ void JitIL::ps_arith(UGeckoInstruction inst)
ibuild.EmitStoreFReg(val, inst.FD);
}

void JitIL::ps_sum(UGeckoInstruction inst)
void JitILBase::ps_sum(UGeckoInstruction inst)
{
// TODO: This operation strikes me as a bit strange...
// perhaps we can optimize it depending on the users?
Expand All @@ -84,7 +83,7 @@ void JitIL::ps_sum(UGeckoInstruction inst)
}


void JitIL::ps_muls(UGeckoInstruction inst)
void JitILBase::ps_muls(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITPairedOff)
Expand All @@ -109,7 +108,7 @@ void JitIL::ps_muls(UGeckoInstruction inst)


//TODO: find easy cases and optimize them, do a breakout like ps_arith
void JitIL::ps_mergeXX(UGeckoInstruction inst)
void JitILBase::ps_mergeXX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITPairedOff)
Expand Down Expand Up @@ -142,7 +141,7 @@ void JitIL::ps_mergeXX(UGeckoInstruction inst)
}


void JitIL::ps_maddXX(UGeckoInstruction inst)
void JitILBase::ps_maddXX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITPairedOff)
Expand Down
Expand Up @@ -9,15 +9,10 @@
#include "../../HW/SystemTimers.h"
#include "../PowerPC.h"
#include "../PPCTables.h"
#include "x64Emitter.h"
#include "x64ABI.h"

#include "JitIL.h"
#include "JitILBase.h"

//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START

void JitIL::mtspr(UGeckoInstruction inst)
void JitILBase::mtspr(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITSystemRegistersOff)
Expand Down Expand Up @@ -53,7 +48,7 @@ void JitIL::mtspr(UGeckoInstruction inst)
}
}

void JitIL::mfspr(UGeckoInstruction inst)
void JitILBase::mfspr(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITSystemRegistersOff)
Expand Down Expand Up @@ -90,29 +85,29 @@ void JitIL::mfspr(UGeckoInstruction inst)
// =======================================================================================
// Don't interpret this, if we do we get thrown out
// --------------
void JitIL::mtmsr(UGeckoInstruction inst)
void JitILBase::mtmsr(UGeckoInstruction inst)
{
ibuild.EmitStoreMSR(ibuild.EmitLoadGReg(inst.RS), ibuild.EmitIntConst(js.compilerPC));
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
}
// ==============


void JitIL::mfmsr(UGeckoInstruction inst)
void JitILBase::mfmsr(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITSystemRegistersOff)
ibuild.EmitStoreGReg(ibuild.EmitLoadMSR(), inst.RD);
}

void JitIL::mftb(UGeckoInstruction inst)
void JitILBase::mftb(UGeckoInstruction inst)
{
INSTRUCTION_START;
JITDISABLE(bJITSystemRegistersOff)
mfspr(inst);
}

void JitIL::mfcr(UGeckoInstruction inst)
void JitILBase::mfcr(UGeckoInstruction inst)
{
INSTRUCTION_START;
JITDISABLE(bJITSystemRegistersOff)
Expand All @@ -126,7 +121,7 @@ void JitIL::mfcr(UGeckoInstruction inst)
ibuild.EmitStoreGReg(d, inst.RD);
}

void JitIL::mtcrf(UGeckoInstruction inst)
void JitILBase::mtcrf(UGeckoInstruction inst)
{
INSTRUCTION_START;
JITDISABLE(bJITSystemRegistersOff)
Expand All @@ -144,7 +139,7 @@ void JitIL::mtcrf(UGeckoInstruction inst)
}
}

void JitIL::mcrf(UGeckoInstruction inst)
void JitILBase::mcrf(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITSystemRegistersOff)
Expand All @@ -155,7 +150,7 @@ void JitIL::mcrf(UGeckoInstruction inst)
}
}

void JitIL::crXX(UGeckoInstruction inst)
void JitILBase::crXX(UGeckoInstruction inst)
{
// Ported from Jit_SystemRegister.cpp

Expand Down
12 changes: 12 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitInterface.cpp
Expand Up @@ -21,6 +21,8 @@
#ifdef _M_ARM
#include "JitArm32/Jit.h"
#include "JitArm32/JitArm_Tables.h"
#include "JitArmIL/JitIL.h"
#include "JitArmIL/JitIL_Tables.h"
#endif

#include "Profiler.h"
Expand Down Expand Up @@ -64,6 +66,11 @@ namespace JitInterface
ptr = new JitArm();
break;
}
case 4:
{
ptr = new JitArmIL();
break;
}
#endif
default:
{
Expand Down Expand Up @@ -99,6 +106,11 @@ namespace JitInterface
JitArmTables::InitTables();
break;
}
case 4:
{
JitArmILTables::InitTables();
break;
}
#endif
default:
{
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/x64MemTools.cpp
Expand Up @@ -22,7 +22,7 @@
namespace EMM
{

#if defined __APPLE__ || defined __linux__ || defined __FreeBSD__
#if (defined __APPLE__ || defined __linux__ || defined __FreeBSD__) && !defined(ANDROID)
#include <execinfo.h>
void print_trace(const char * msg)
{
Expand Down
1 change: 1 addition & 0 deletions Source/Core/DolphinWX/Src/ConfigMain.cpp
Expand Up @@ -43,6 +43,7 @@ const CPUCore CPUCores[] = {
{0, wxTRANSLATE("Interpreter (VERY slow)")},
#ifdef _M_ARM
{3, wxTRANSLATE("Arm JIT (experimental)")},
{4, wxTRANSLATE("Arm JITIL (experimental)")},
#else
{1, wxTRANSLATE("JIT Recompiler (recommended)")},
{2, wxTRANSLATE("JITIL experimental recompiler")},
Expand Down