Merge pull request #11400 from Pokechu22/better-ppc-tables

Use C++20 features to create opcode tables at compile time
This commit is contained in:
Admiral H. Curtiss 2023-03-17 04:13:25 +01:00 committed by GitHub
commit 49b495f756
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 1240 additions and 735 deletions

View file

@ -83,4 +83,17 @@ static_assert(!IsNOf<int, 1, int, int>::value);
static_assert(IsNOf<int, 2, int, int>::value);
static_assert(IsNOf<int, 2, int, short>::value); // Type conversions ARE allowed
static_assert(!IsNOf<int, 2, int, char*>::value);
// TODO: This can be replaced with std::array's fill() once C++20 is fully supported.
// Prior to C++20, std::array's fill() function is, unfortunately, not constexpr.
// Ditto for <algorithm>'s std::fill. Although Dolphin targets C++20, Android doesn't
// seem to properly support constexpr fill(), so we need this for now.
template <typename T1, size_t N, typename T2>
constexpr void Fill(std::array<T1, N>& array, const T2& value)
{
for (auto& entry : array)
{
entry = value;
}
}
} // namespace Common

View file

@ -270,7 +270,7 @@ void CachedInterpreter::Jit(u32 address)
{
PPCAnalyst::CodeOp& op = m_code_buffer[i];
js.downcountAmount += op.opinfo->numCycles;
js.downcountAmount += op.opinfo->num_cycles;
if (op.opinfo->flags & FL_LOADSTORE)
++js.numLoadStoreInst;
if (op.opinfo->flags & FL_USE_FPU)
@ -301,7 +301,7 @@ void CachedInterpreter::Jit(u32 address)
js.firstFPInstructionFound = true;
}
m_code.emplace_back(PPCTables::GetInterpreterOp(op.inst), op.inst);
m_code.emplace_back(Interpreter::GetInterpreterOp(op.inst), op.inst);
if (memcheck)
m_code.emplace_back(CheckDSI, js.downcountAmount);
if (check_program_exception)

View file

@ -34,14 +34,6 @@ u32 last_pc;
bool Interpreter::m_end_block;
// function tables
std::array<Interpreter::Instruction, 64> Interpreter::m_op_table;
std::array<Interpreter::Instruction, 1024> Interpreter::m_op_table4;
std::array<Interpreter::Instruction, 1024> Interpreter::m_op_table19;
std::array<Interpreter::Instruction, 1024> Interpreter::m_op_table31;
std::array<Interpreter::Instruction, 32> Interpreter::m_op_table59;
std::array<Interpreter::Instruction, 1024> Interpreter::m_op_table63;
namespace
{
// Determines whether or not the given instruction is one where its execution
@ -79,30 +71,8 @@ void UpdatePC()
}
} // Anonymous namespace
void Interpreter::RunTable4(UGeckoInstruction inst)
{
m_op_table4[inst.SUBOP10](inst);
}
void Interpreter::RunTable19(UGeckoInstruction inst)
{
m_op_table19[inst.SUBOP10](inst);
}
void Interpreter::RunTable31(UGeckoInstruction inst)
{
m_op_table31[inst.SUBOP10](inst);
}
void Interpreter::RunTable59(UGeckoInstruction inst)
{
m_op_table59[inst.SUBOP5](inst);
}
void Interpreter::RunTable63(UGeckoInstruction inst)
{
m_op_table63[inst.SUBOP10](inst);
}
void Interpreter::Init()
{
InitializeInstructionTables();
m_end_block = false;
}
@ -150,12 +120,17 @@ int Interpreter::SingleStepInner()
if (HandleFunctionHooking(PowerPC::ppcState.pc))
{
UpdatePC();
return PPCTables::GetOpInfo(m_prev_inst)->numCycles;
// TODO: Does it make sense to use m_prev_inst here?
// It seems like we should use the num_cycles for the instruction at PC instead
// (m_prev_inst has not yet been updated)
return PPCTables::GetOpInfo(m_prev_inst)->num_cycles;
}
PowerPC::ppcState.npc = PowerPC::ppcState.pc + sizeof(UGeckoInstruction);
m_prev_inst.hex = PowerPC::Read_Opcode(PowerPC::ppcState.pc);
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst);
// Uncomment to trace the interpreter
// if ((PowerPC::ppcState.pc & 0x00FFFFFF) >= 0x000AB54C &&
// (PowerPC::ppcState.pc & 0x00FFFFFF) <= 0x000AB624)
@ -181,7 +156,7 @@ int Interpreter::SingleStepInner()
}
else if (PowerPC::ppcState.msr.FP)
{
m_op_table[m_prev_inst.OPCD](m_prev_inst);
RunInterpreterOp(m_prev_inst);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
{
CheckExceptions();
@ -190,14 +165,14 @@ int Interpreter::SingleStepInner()
else
{
// check if we have to generate a FPU unavailable exception or a program exception.
if (PPCTables::UsesFPU(m_prev_inst))
if ((opinfo->flags & FL_USE_FPU) != 0)
{
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
CheckExceptions();
}
else
{
m_op_table[m_prev_inst.OPCD](m_prev_inst);
RunInterpreterOp(m_prev_inst);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
{
CheckExceptions();
@ -213,10 +188,9 @@ int Interpreter::SingleStepInner()
UpdatePC();
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst);
PowerPC::UpdatePerformanceMonitor(opinfo->numCycles, (opinfo->flags & FL_LOADSTORE) != 0,
PowerPC::UpdatePerformanceMonitor(opinfo->num_cycles, (opinfo->flags & FL_LOADSTORE) != 0,
(opinfo->flags & FL_USE_FPU) != 0, PowerPC::ppcState);
return opinfo->numCycles;
return opinfo->num_cycles;
}
void Interpreter::SingleStep()

View file

@ -262,12 +262,9 @@ public:
static void isync(UGeckoInstruction inst);
using Instruction = void (*)(UGeckoInstruction inst);
static std::array<Instruction, 64> m_op_table;
static std::array<Instruction, 1024> m_op_table4;
static std::array<Instruction, 1024> m_op_table19;
static std::array<Instruction, 1024> m_op_table31;
static std::array<Instruction, 32> m_op_table59;
static std::array<Instruction, 1024> m_op_table63;
static Instruction GetInterpreterOp(UGeckoInstruction inst);
static void RunInterpreterOp(UGeckoInstruction inst);
// singleton
static Interpreter* getInstance();
@ -283,8 +280,6 @@ public:
private:
void CheckExceptions();
static void InitializeInstructionTables();
static bool HandleFunctionHooking(u32 address);
// flag helper

View file

@ -5,492 +5,492 @@
#include <array>
#include "Common/Assert.h"
#include "Common/TypeUtils.h"
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/PPCTables.h"
namespace
{
struct GekkoOPTemplate
struct InterpreterOpTemplate
{
int opcode;
Interpreter::Instruction Inst;
GekkoOPInfo opinfo;
u32 opcode;
Interpreter::Instruction fn;
};
} // namespace
// clang-format off
static GekkoOPInfo unknownopinfo = { "unknown_instruction", OpType::Unknown, FL_ENDBLOCK, 0, 0, 0, 0 };
constexpr std::array<InterpreterOpTemplate, 54> s_primary_table{{
{4, Interpreter::RunTable4}, // RunTable4
{19, Interpreter::RunTable19}, // RunTable19
{31, Interpreter::RunTable31}, // RunTable31
{59, Interpreter::RunTable59}, // RunTable59
{63, Interpreter::RunTable63}, // RunTable63
static std::array<GekkoOPTemplate, 54> primarytable =
{{
{4, Interpreter::RunTable4, {"RunTable4", OpType::Subtable, 0, 0, 0, 0, 0}},
{19, Interpreter::RunTable19, {"RunTable19", OpType::Subtable, 0, 0, 0, 0, 0}},
{31, Interpreter::RunTable31, {"RunTable31", OpType::Subtable, 0, 0, 0, 0, 0}},
{59, Interpreter::RunTable59, {"RunTable59", OpType::Subtable, 0, 0, 0, 0, 0}},
{63, Interpreter::RunTable63, {"RunTable63", OpType::Subtable, 0, 0, 0, 0, 0}},
{16, Interpreter::bcx}, // bcx
{18, Interpreter::bx}, // bx
{16, Interpreter::bcx, {"bcx", OpType::Branch, FL_ENDBLOCK | FL_READ_CR_BI, 1, 0, 0, 0}},
{18, Interpreter::bx, {"bx", OpType::Branch, FL_ENDBLOCK, 1, 0, 0, 0}},
{3, Interpreter::twi}, // twi
{17, Interpreter::sc}, // sc
{3, Interpreter::twi, {"twi", OpType::System, FL_IN_A | FL_ENDBLOCK, 1, 0, 0, 0}},
{17, Interpreter::sc, {"sc", OpType::System, FL_ENDBLOCK, 2, 0, 0, 0}},
{7, Interpreter::mulli}, // mulli
{8, Interpreter::subfic}, // subfic
{10, Interpreter::cmpli}, // cmpli
{11, Interpreter::cmpi}, // cmpi
{12, Interpreter::addic}, // addic
{13, Interpreter::addic_rc}, // addic_rc
{14, Interpreter::addi}, // addi
{15, Interpreter::addis}, // addis
{7, Interpreter::mulli, {"mulli", OpType::Integer, FL_OUT_D | FL_IN_A, 3, 0, 0, 0}},
{8, Interpreter::subfic, {"subfic", OpType::Integer, FL_OUT_D | FL_IN_A | FL_SET_CA, 1, 0, 0, 0}},
{10, Interpreter::cmpli, {"cmpli", OpType::Integer, FL_IN_A | FL_SET_CRn, 1, 0, 0, 0}},
{11, Interpreter::cmpi, {"cmpi", OpType::Integer, FL_IN_A | FL_SET_CRn, 1, 0, 0, 0}},
{12, Interpreter::addic, {"addic", OpType::Integer, FL_OUT_D | FL_IN_A | FL_SET_CA, 1, 0, 0, 0}},
{13, Interpreter::addic_rc, {"addic_rc", OpType::Integer, FL_OUT_D | FL_IN_A | FL_SET_CA | FL_SET_CR0, 1, 0, 0, 0}},
{14, Interpreter::addi, {"addi", OpType::Integer, FL_OUT_D | FL_IN_A0, 1, 0, 0, 0}},
{15, Interpreter::addis, {"addis", OpType::Integer, FL_OUT_D | FL_IN_A0, 1, 0, 0, 0}},
{20, Interpreter::rlwimix}, // rlwimix
{21, Interpreter::rlwinmx}, // rlwinmx
{23, Interpreter::rlwnmx}, // rlwnmx
{20, Interpreter::rlwimix, {"rlwimix", OpType::Integer, FL_OUT_A | FL_IN_A | FL_IN_S | FL_RC_BIT, 1, 0, 0, 0}},
{21, Interpreter::rlwinmx, {"rlwinmx", OpType::Integer, FL_OUT_A | FL_IN_S | FL_RC_BIT, 1, 0, 0, 0}},
{23, Interpreter::rlwnmx, {"rlwnmx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}},
{24, Interpreter::ori}, // ori
{25, Interpreter::oris}, // oris
{26, Interpreter::xori}, // xori
{27, Interpreter::xoris}, // xoris
{28, Interpreter::andi_rc}, // andi_rc
{29, Interpreter::andis_rc}, // andis_rc
{24, Interpreter::ori, {"ori", OpType::Integer, FL_OUT_A | FL_IN_S, 1, 0, 0, 0}},
{25, Interpreter::oris, {"oris", OpType::Integer, FL_OUT_A | FL_IN_S, 1, 0, 0, 0}},
{26, Interpreter::xori, {"xori", OpType::Integer, FL_OUT_A | FL_IN_S, 1, 0, 0, 0}},
{27, Interpreter::xoris, {"xoris", OpType::Integer, FL_OUT_A | FL_IN_S, 1, 0, 0, 0}},
{28, Interpreter::andi_rc, {"andi_rc", OpType::Integer, FL_OUT_A | FL_IN_S | FL_SET_CR0, 1, 0, 0, 0}},
{29, Interpreter::andis_rc, {"andis_rc", OpType::Integer, FL_OUT_A | FL_IN_S | FL_SET_CR0, 1, 0, 0, 0}},
{32, Interpreter::lwz}, // lwz
{33, Interpreter::lwzu}, // lwzu
{34, Interpreter::lbz}, // lbz
{35, Interpreter::lbzu}, // lbzu
{40, Interpreter::lhz}, // lhz
{41, Interpreter::lhzu}, // lhzu
{32, Interpreter::lwz, {"lwz", OpType::Load, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE, 1, 0, 0, 0}},
{33, Interpreter::lwzu, {"lwzu", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE, 1, 0, 0, 0}},
{34, Interpreter::lbz, {"lbz", OpType::Load, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE, 1, 0, 0, 0}},
{35, Interpreter::lbzu, {"lbzu", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE, 1, 0, 0, 0}},
{40, Interpreter::lhz, {"lhz", OpType::Load, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE, 1, 0, 0, 0}},
{41, Interpreter::lhzu, {"lhzu", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE, 1, 0, 0, 0}},
{42, Interpreter::lha}, // lha
{43, Interpreter::lhau}, // lhau
{42, Interpreter::lha, {"lha", OpType::Load, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE, 1, 0, 0, 0}},
{43, Interpreter::lhau, {"lhau", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE, 1, 0, 0, 0}},
{44, Interpreter::sth}, // sth
{45, Interpreter::sthu}, // sthu
{36, Interpreter::stw}, // stw
{37, Interpreter::stwu}, // stwu
{38, Interpreter::stb}, // stb
{39, Interpreter::stbu}, // stbu
{44, Interpreter::sth, {"sth", OpType::Store, FL_IN_A0 | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}},
{45, Interpreter::sthu, {"sthu", OpType::Store, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}},
{36, Interpreter::stw, {"stw", OpType::Store, FL_IN_A0 | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}},
{37, Interpreter::stwu, {"stwu", OpType::Store, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}},
{38, Interpreter::stb, {"stb", OpType::Store, FL_IN_A0 | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}},
{39, Interpreter::stbu, {"stbu", OpType::Store, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}},
{46, Interpreter::lmw}, // lmw
{47, Interpreter::stmw}, // stmw
{46, Interpreter::lmw, {"lmw", OpType::System, FL_EVIL | FL_IN_A0 | FL_LOADSTORE, 11, 0, 0, 0}},
{47, Interpreter::stmw, {"stmw", OpType::System, FL_EVIL | FL_IN_A0 | FL_LOADSTORE, 11, 0, 0, 0}},
{48, Interpreter::lfs}, // lfs
{49, Interpreter::lfsu}, // lfsu
{50, Interpreter::lfd}, // lfd
{51, Interpreter::lfdu}, // lfdu
{48, Interpreter::lfs, {"lfs", OpType::LoadFP, FL_OUT_FLOAT_D | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{49, Interpreter::lfsu, {"lfsu", OpType::LoadFP, FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{50, Interpreter::lfd, {"lfd", OpType::LoadFP, FL_INOUT_FLOAT_D | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{51, Interpreter::lfdu, {"lfdu", OpType::LoadFP, FL_INOUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{52, Interpreter::stfs}, // stfs
{53, Interpreter::stfsu}, // stfsu
{54, Interpreter::stfd}, // stfd
{55, Interpreter::stfdu}, // stfdu
{52, Interpreter::stfs, {"stfs", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{53, Interpreter::stfsu, {"stfsu", OpType::StoreFP, FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{54, Interpreter::stfd, {"stfd", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{55, Interpreter::stfdu, {"stfdu", OpType::StoreFP, FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{56, Interpreter::psq_l}, // psq_l
{57, Interpreter::psq_lu}, // psq_lu
{60, Interpreter::psq_st}, // psq_st
{61, Interpreter::psq_stu}, // psq_stu
{56, Interpreter::psq_l, {"psq_l", OpType::LoadPS, FL_OUT_FLOAT_D | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{57, Interpreter::psq_lu, {"psq_lu", OpType::LoadPS, FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{60, Interpreter::psq_st, {"psq_st", OpType::StorePS, FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{61, Interpreter::psq_stu, {"psq_stu", OpType::StorePS, FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
//missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58
// missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58
}};
static std::array<GekkoOPTemplate, 13> table4 =
{{ //SUBOP10
{0, Interpreter::ps_cmpu0, {"ps_cmpu0", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{32, Interpreter::ps_cmpo0, {"ps_cmpo0", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{40, Interpreter::ps_neg, {"ps_neg", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{136, Interpreter::ps_nabs, {"ps_nabs", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{264, Interpreter::ps_abs, {"ps_abs", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{64, Interpreter::ps_cmpu1, {"ps_cmpu1", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{72, Interpreter::ps_mr, {"ps_mr", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{96, Interpreter::ps_cmpo1, {"ps_cmpo1", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{528, Interpreter::ps_merge00, {"ps_merge00", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{560, Interpreter::ps_merge01, {"ps_merge01", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{592, Interpreter::ps_merge10, {"ps_merge10", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{624, Interpreter::ps_merge11, {"ps_merge11", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
constexpr std::array<InterpreterOpTemplate, 13> s_table4{{
// SUBOP10
{0, Interpreter::ps_cmpu0}, // ps_cmpu0
{32, Interpreter::ps_cmpo0}, // ps_cmpo0
{40, Interpreter::ps_neg}, // ps_neg
{136, Interpreter::ps_nabs}, // ps_nabs
{264, Interpreter::ps_abs}, // ps_abs
{64, Interpreter::ps_cmpu1}, // ps_cmpu1
{72, Interpreter::ps_mr}, // ps_mr
{96, Interpreter::ps_cmpo1}, // ps_cmpo1
{528, Interpreter::ps_merge00}, // ps_merge00
{560, Interpreter::ps_merge01}, // ps_merge01
{592, Interpreter::ps_merge10}, // ps_merge10
{624, Interpreter::ps_merge11}, // ps_merge11
{1014, Interpreter::dcbz_l, {"dcbz_l", OpType::System, FL_IN_A0B | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{1014, Interpreter::dcbz_l}, // dcbz_l
}};
static std::array<GekkoOPTemplate, 17> table4_2 =
{{
{10, Interpreter::ps_sum0, {"ps_sum0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{11, Interpreter::ps_sum1, {"ps_sum1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{12, Interpreter::ps_muls0, {"ps_muls0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{13, Interpreter::ps_muls1, {"ps_muls1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{14, Interpreter::ps_madds0, {"ps_madds0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{15, Interpreter::ps_madds1, {"ps_madds1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{18, Interpreter::ps_div, {"ps_div", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 17, 0, 0, 0}},
{20, Interpreter::ps_sub, {"ps_sub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{21, Interpreter::ps_add, {"ps_add", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{23, Interpreter::ps_sel, {"ps_sel", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_IN_FLOAT_BC_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{24, Interpreter::ps_res, {"ps_res", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 1, 0, 0, 0}},
{25, Interpreter::ps_mul, {"ps_mul", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{26, Interpreter::ps_rsqrte, {"ps_rsqrte", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 2, 0, 0, 0}},
{28, Interpreter::ps_msub, {"ps_msub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{29, Interpreter::ps_madd, {"ps_madd", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{30, Interpreter::ps_nmsub, {"ps_nmsub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{31, Interpreter::ps_nmadd, {"ps_nmadd", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
constexpr std::array<InterpreterOpTemplate, 17> s_table4_2{{
{10, Interpreter::ps_sum0}, // ps_sum0
{11, Interpreter::ps_sum1}, // ps_sum1
{12, Interpreter::ps_muls0}, // ps_muls0
{13, Interpreter::ps_muls1}, // ps_muls1
{14, Interpreter::ps_madds0}, // ps_madds0
{15, Interpreter::ps_madds1}, // ps_madds1
{18, Interpreter::ps_div}, // ps_div
{20, Interpreter::ps_sub}, // ps_sub
{21, Interpreter::ps_add}, // ps_add
{23, Interpreter::ps_sel}, // ps_sel
{24, Interpreter::ps_res}, // ps_res
{25, Interpreter::ps_mul}, // ps_mul
{26, Interpreter::ps_rsqrte}, // ps_rsqrte
{28, Interpreter::ps_msub}, // ps_msub
{29, Interpreter::ps_madd}, // ps_madd
{30, Interpreter::ps_nmsub}, // ps_nmsub
{31, Interpreter::ps_nmadd}, // ps_nmadd
}};
static std::array<GekkoOPTemplate, 4> table4_3 =
{{
{6, Interpreter::psq_lx, {"psq_lx", OpType::LoadPS, FL_OUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{7, Interpreter::psq_stx, {"psq_stx", OpType::StorePS, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{38, Interpreter::psq_lux, {"psq_lux", OpType::LoadPS, FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_AB | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{39, Interpreter::psq_stux, {"psq_stux", OpType::StorePS, FL_IN_FLOAT_S | FL_OUT_A | FL_IN_AB | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
constexpr std::array<InterpreterOpTemplate, 4> s_table4_3{{
{6, Interpreter::psq_lx}, // psq_lx
{7, Interpreter::psq_stx}, // psq_stx
{38, Interpreter::psq_lux}, // psq_lux
{39, Interpreter::psq_stux}, // psq_stux
}};
static std::array<GekkoOPTemplate, 13> table19 =
{{
{528, Interpreter::bcctrx, {"bcctrx", OpType::Branch, FL_ENDBLOCK | FL_READ_CR_BI, 1, 0, 0, 0}},
{16, Interpreter::bclrx, {"bclrx", OpType::Branch, FL_ENDBLOCK | FL_READ_CR_BI, 1, 0, 0, 0}},
{257, Interpreter::crand, {"crand", OpType::CR, FL_EVIL, 1, 0, 0, 0}},
{129, Interpreter::crandc, {"crandc", OpType::CR, FL_EVIL, 1, 0, 0, 0}},
{289, Interpreter::creqv, {"creqv", OpType::CR, FL_EVIL, 1, 0, 0, 0}},
{225, Interpreter::crnand, {"crnand", OpType::CR, FL_EVIL, 1, 0, 0, 0}},
{33, Interpreter::crnor, {"crnor", OpType::CR, FL_EVIL, 1, 0, 0, 0}},
{449, Interpreter::cror, {"cror", OpType::CR, FL_EVIL, 1, 0, 0, 0}},
{417, Interpreter::crorc, {"crorc", OpType::CR, FL_EVIL, 1, 0, 0, 0}},
{193, Interpreter::crxor, {"crxor", OpType::CR, FL_EVIL, 1, 0, 0, 0}},
constexpr std::array<InterpreterOpTemplate, 13> s_table19{{
{528, Interpreter::bcctrx}, // bcctrx
{16, Interpreter::bclrx}, // bclrx
{257, Interpreter::crand}, // crand
{129, Interpreter::crandc}, // crandc
{289, Interpreter::creqv}, // creqv
{225, Interpreter::crnand}, // crnand
{33, Interpreter::crnor}, // crnor
{449, Interpreter::cror}, // cror
{417, Interpreter::crorc}, // crorc
{193, Interpreter::crxor}, // crxor
{150, Interpreter::isync, {"isync", OpType::InstructionCache, FL_EVIL, 1, 0, 0, 0}},
{0, Interpreter::mcrf, {"mcrf", OpType::System, FL_EVIL | FL_SET_CRn | FL_READ_CRn, 1, 0, 0, 0}},
{150, Interpreter::isync}, // isync
{0, Interpreter::mcrf}, // mcrf
{50, Interpreter::rfi, {"rfi", OpType::System, FL_ENDBLOCK | FL_CHECKEXCEPTIONS | FL_PROGRAMEXCEPTION, 2, 0, 0, 0}},
{50, Interpreter::rfi}, // rfi
}};
static std::array<GekkoOPTemplate, 107> table31 =
{{
{266, Interpreter::addx, {"addx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 1, 0, 0, 0}},
{778, Interpreter::addx, {"addox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}},
{10, Interpreter::addcx, {"addcx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}},
{522, Interpreter::addcx, {"addcox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}},
{138, Interpreter::addex, {"addex", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}},
{650, Interpreter::addex, {"addeox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}},
{234, Interpreter::addmex, {"addmex", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}},
{746, Interpreter::addmex, {"addmeox", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}},
{202, Interpreter::addzex, {"addzex", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}},
{714, Interpreter::addzex, {"addzeox", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}},
{491, Interpreter::divwx, {"divwx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 40, 0, 0, 0}},
{1003, Interpreter::divwx, {"divwox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE, 40, 0, 0, 0}},
{459, Interpreter::divwux, {"divwux", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 40, 0, 0, 0}},
{971, Interpreter::divwux, {"divwuox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE, 40, 0, 0, 0}},
{75, Interpreter::mulhwx, {"mulhwx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 5, 0, 0, 0}},
{11, Interpreter::mulhwux, {"mulhwux", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 5, 0, 0, 0}},
{235, Interpreter::mullwx, {"mullwx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 5, 0, 0, 0}},
{747, Interpreter::mullwx, {"mullwox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE, 5, 0, 0, 0}},
{104, Interpreter::negx, {"negx", OpType::Integer, FL_OUT_D | FL_IN_A | FL_RC_BIT, 1, 0, 0, 0}},
{616, Interpreter::negx, {"negox", OpType::Integer, FL_OUT_D | FL_IN_A | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}},
{40, Interpreter::subfx, {"subfx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 1, 0, 0, 0}},
{552, Interpreter::subfx, {"subfox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}},
{8, Interpreter::subfcx, {"subfcx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}},
{520, Interpreter::subfcx, {"subfcox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}},
{136, Interpreter::subfex, {"subfex", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}},
{648, Interpreter::subfex, {"subfeox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}},
{232, Interpreter::subfmex, {"subfmex", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}},
{744, Interpreter::subfmex, {"subfmeox",OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}},
{200, Interpreter::subfzex, {"subfzex", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}},
{712, Interpreter::subfzex, {"subfzeox",OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}},
constexpr std::array<InterpreterOpTemplate, 107> s_table31{{
{266, Interpreter::addx}, // addx
{778, Interpreter::addx}, // addox
{10, Interpreter::addcx}, // addcx
{522, Interpreter::addcx}, // addcox
{138, Interpreter::addex}, // addex
{650, Interpreter::addex}, // addeox
{234, Interpreter::addmex}, // addmex
{746, Interpreter::addmex}, // addmeox
{202, Interpreter::addzex}, // addzex
{714, Interpreter::addzex}, // addzeox
{491, Interpreter::divwx}, // divwx
{1003, Interpreter::divwx}, // divwox
{459, Interpreter::divwux}, // divwux
{971, Interpreter::divwux}, // divwuox
{75, Interpreter::mulhwx}, // mulhwx
{11, Interpreter::mulhwux}, // mulhwux
{235, Interpreter::mullwx}, // mullwx
{747, Interpreter::mullwx}, // mullwox
{104, Interpreter::negx}, // negx
{616, Interpreter::negx}, // negox
{40, Interpreter::subfx}, // subfx
{552, Interpreter::subfx}, // subfox
{8, Interpreter::subfcx}, // subfcx
{520, Interpreter::subfcx}, // subfcox
{136, Interpreter::subfex}, // subfex
{648, Interpreter::subfex}, // subfeox
{232, Interpreter::subfmex}, // subfmex
{744, Interpreter::subfmex}, // subfmeox
{200, Interpreter::subfzex}, // subfzex
{712, Interpreter::subfzex}, // subfzeox
{28, Interpreter::andx, {"andx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}},
{60, Interpreter::andcx, {"andcx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}},
{444, Interpreter::orx, {"orx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}},
{124, Interpreter::norx, {"norx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}},
{316, Interpreter::xorx, {"xorx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}},
{412, Interpreter::orcx, {"orcx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}},
{476, Interpreter::nandx, {"nandx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}},
{284, Interpreter::eqvx, {"eqvx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}},
{0, Interpreter::cmp, {"cmp", OpType::Integer, FL_IN_AB | FL_SET_CRn, 1, 0, 0, 0}},
{32, Interpreter::cmpl, {"cmpl", OpType::Integer, FL_IN_AB | FL_SET_CRn, 1, 0, 0, 0}},
{26, Interpreter::cntlzwx, {"cntlzwx",OpType::Integer, FL_OUT_A | FL_IN_S | FL_RC_BIT, 1, 0, 0, 0}},
{922, Interpreter::extshx, {"extshx", OpType::Integer, FL_OUT_A | FL_IN_S | FL_RC_BIT, 1, 0, 0, 0}},
{954, Interpreter::extsbx, {"extsbx", OpType::Integer, FL_OUT_A | FL_IN_S | FL_RC_BIT, 1, 0, 0, 0}},
{536, Interpreter::srwx, {"srwx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}},
{792, Interpreter::srawx, {"srawx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}},
{824, Interpreter::srawix, {"srawix", OpType::Integer, FL_OUT_A | FL_IN_S | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}},
{24, Interpreter::slwx, {"slwx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}},
{28, Interpreter::andx}, // andx
{60, Interpreter::andcx}, // andcx
{444, Interpreter::orx}, // orx
{124, Interpreter::norx}, // norx
{316, Interpreter::xorx}, // xorx
{412, Interpreter::orcx}, // orcx
{476, Interpreter::nandx}, // nandx
{284, Interpreter::eqvx}, // eqvx
{0, Interpreter::cmp}, // cmp
{32, Interpreter::cmpl}, // cmpl
{26, Interpreter::cntlzwx}, // cntlzwx
{922, Interpreter::extshx}, // extshx
{954, Interpreter::extsbx}, // extsbx
{536, Interpreter::srwx}, // srwx
{792, Interpreter::srawx}, // srawx
{824, Interpreter::srawix}, // srawix
{24, Interpreter::slwx}, // slwx
{54, Interpreter::dcbst, {"dcbst", OpType::DataCache, FL_IN_A0B | FL_LOADSTORE, 5, 0, 0, 0}},
{86, Interpreter::dcbf, {"dcbf", OpType::DataCache, FL_IN_A0B | FL_LOADSTORE, 5, 0, 0, 0}},
{246, Interpreter::dcbtst, {"dcbtst", OpType::DataCache, 0, 2, 0, 0, 0}},
{278, Interpreter::dcbt, {"dcbt", OpType::DataCache, 0, 2, 0, 0, 0}},
{470, Interpreter::dcbi, {"dcbi", OpType::DataCache, FL_IN_A0B | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 5, 0, 0, 0}},
{758, Interpreter::dcba, {"dcba", OpType::DataCache, 0, 5, 0, 0, 0}},
{1014, Interpreter::dcbz, {"dcbz", OpType::DataCache, FL_IN_A0B | FL_LOADSTORE, 5, 0, 0, 0}},
{54, Interpreter::dcbst}, // dcbst
{86, Interpreter::dcbf}, // dcbf
{246, Interpreter::dcbtst}, // dcbtst
{278, Interpreter::dcbt}, // dcbt
{470, Interpreter::dcbi}, // dcbi
{758, Interpreter::dcba}, // dcba
{1014, Interpreter::dcbz}, // dcbz
//load word
{23, Interpreter::lwzx, {"lwzx", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
{55, Interpreter::lwzux, {"lwzux", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}},
// load word
{23, Interpreter::lwzx}, // lwzx
{55, Interpreter::lwzux}, // lwzux
//load halfword
{279, Interpreter::lhzx, {"lhzx", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
{311, Interpreter::lhzux, {"lhzux", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}},
// load halfword
{279, Interpreter::lhzx}, // lhzx
{311, Interpreter::lhzux}, // lhzux
//load halfword signextend
{343, Interpreter::lhax, {"lhax", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
{375, Interpreter::lhaux, {"lhaux", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}},
// load halfword signextend
{343, Interpreter::lhax}, // lhax
{375, Interpreter::lhaux}, // lhaux
//load byte
{87, Interpreter::lbzx, {"lbzx", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
{119, Interpreter::lbzux, {"lbzux", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}},
// load byte
{87, Interpreter::lbzx}, // lbzx
{119, Interpreter::lbzux}, // lbzux
//load byte reverse
{534, Interpreter::lwbrx, {"lwbrx", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
{790, Interpreter::lhbrx, {"lhbrx", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
// load byte reverse
{534, Interpreter::lwbrx}, // lwbrx
{790, Interpreter::lhbrx}, // lhbrx
// Conditional load/store (Wii SMP)
{150, Interpreter::stwcxd, {"stwcxd", OpType::Store, FL_EVIL | FL_IN_S | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE, 1, 0, 0, 0}},
{20, Interpreter::lwarx, {"lwarx", OpType::Load, FL_EVIL | FL_OUT_D | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE, 1, 0, 0, 0}},
// Conditional load/store (Wii SMP)
{150, Interpreter::stwcxd}, // stwcxd
{20, Interpreter::lwarx}, // lwarx
//load string (Inst these)
{533, Interpreter::lswx, {"lswx", OpType::Load, FL_EVIL | FL_IN_A0B | FL_OUT_D | FL_LOADSTORE, 1, 0, 0, 0}},
{597, Interpreter::lswi, {"lswi", OpType::Load, FL_EVIL | FL_IN_A0 | FL_OUT_D | FL_LOADSTORE, 1, 0, 0, 0}},
// load string (Inst these)
{533, Interpreter::lswx}, // lswx
{597, Interpreter::lswi}, // lswi
//store word
{151, Interpreter::stwx, {"stwx", OpType::Store, FL_IN_S | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
{183, Interpreter::stwux, {"stwux", OpType::Store, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}},
// store word
{151, Interpreter::stwx}, // stwx
{183, Interpreter::stwux}, // stwux
//store halfword
{407, Interpreter::sthx, {"sthx", OpType::Store, FL_IN_S | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
{439, Interpreter::sthux, {"sthux", OpType::Store, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}},
// store halfword
{407, Interpreter::sthx}, // sthx
{439, Interpreter::sthux}, // sthux
//store byte
{215, Interpreter::stbx, {"stbx", OpType::Store, FL_IN_S | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
{247, Interpreter::stbux, {"stbux", OpType::Store, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}},
// store byte
{215, Interpreter::stbx}, // stbx
{247, Interpreter::stbux}, // stbux
//store bytereverse
{662, Interpreter::stwbrx, {"stwbrx", OpType::Store, FL_IN_S | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
{918, Interpreter::sthbrx, {"sthbrx", OpType::Store, FL_IN_S | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
// store bytereverse
{662, Interpreter::stwbrx}, // stwbrx
{918, Interpreter::sthbrx}, // sthbrx
{661, Interpreter::stswx, {"stswx", OpType::Store, FL_EVIL | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}},
{725, Interpreter::stswi, {"stswi", OpType::Store, FL_EVIL | FL_IN_A0 | FL_LOADSTORE, 1, 0, 0, 0}},
{661, Interpreter::stswx}, // stswx
{725, Interpreter::stswi}, // stswi
// fp load/store
{535, Interpreter::lfsx, {"lfsx", OpType::LoadFP, FL_OUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{567, Interpreter::lfsux, {"lfsux", OpType::LoadFP, FL_OUT_FLOAT_D | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{599, Interpreter::lfdx, {"lfdx", OpType::LoadFP, FL_INOUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{631, Interpreter::lfdux, {"lfdux", OpType::LoadFP, FL_INOUT_FLOAT_D | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
// fp load/store
{535, Interpreter::lfsx}, // lfsx
{567, Interpreter::lfsux}, // lfsux
{599, Interpreter::lfdx}, // lfdx
{631, Interpreter::lfdux}, // lfdux
{663, Interpreter::stfsx, {"stfsx", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{695, Interpreter::stfsux, {"stfsux", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{727, Interpreter::stfdx, {"stfdx", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{759, Interpreter::stfdux, {"stfdux", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{983, Interpreter::stfiwx, {"stfiwx", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}},
{663, Interpreter::stfsx}, // stfsx
{695, Interpreter::stfsux}, // stfsux
{727, Interpreter::stfdx}, // stfdx
{759, Interpreter::stfdux}, // stfdux
{983, Interpreter::stfiwx}, // stfiwx
{19, Interpreter::mfcr, {"mfcr", OpType::System, FL_OUT_D | FL_READ_ALL_CR, 1, 0, 0, 0}},
{83, Interpreter::mfmsr, {"mfmsr", OpType::System, FL_OUT_D | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{144, Interpreter::mtcrf, {"mtcrf", OpType::System, FL_IN_S | FL_SET_ALL_CR | FL_READ_ALL_CR, 1, 0, 0, 0}},
{146, Interpreter::mtmsr, {"mtmsr", OpType::System, FL_IN_S | FL_ENDBLOCK | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{210, Interpreter::mtsr, {"mtsr", OpType::System, FL_IN_S | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{242, Interpreter::mtsrin, {"mtsrin", OpType::System, FL_IN_SB | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{339, Interpreter::mfspr, {"mfspr", OpType::SPR, FL_OUT_D | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{467, Interpreter::mtspr, {"mtspr", OpType::SPR, FL_IN_S | FL_PROGRAMEXCEPTION, 2, 0, 0, 0}},
{371, Interpreter::mftb, {"mftb", OpType::System, FL_OUT_D | FL_TIMER | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{512, Interpreter::mcrxr, {"mcrxr", OpType::System, FL_SET_CRn | FL_READ_CA | FL_SET_CA, 1, 0, 0, 0}},
{595, Interpreter::mfsr, {"mfsr", OpType::System, FL_OUT_D | FL_PROGRAMEXCEPTION, 3, 0, 0, 0}},
{659, Interpreter::mfsrin, {"mfsrin", OpType::System, FL_OUT_D | FL_IN_B | FL_PROGRAMEXCEPTION, 3, 0, 0, 0}},
{19, Interpreter::mfcr}, // mfcr
{83, Interpreter::mfmsr}, // mfmsr
{144, Interpreter::mtcrf}, // mtcrf
{146, Interpreter::mtmsr}, // mtmsr
{210, Interpreter::mtsr}, // mtsr
{242, Interpreter::mtsrin}, // mtsrin
{339, Interpreter::mfspr}, // mfspr
{467, Interpreter::mtspr}, // mtspr
{371, Interpreter::mftb}, // mftb
{512, Interpreter::mcrxr}, // mcrxr
{595, Interpreter::mfsr}, // mfsr
{659, Interpreter::mfsrin}, // mfsrin
{4, Interpreter::tw, {"tw", OpType::System, FL_IN_AB | FL_ENDBLOCK, 2, 0, 0, 0}},
{598, Interpreter::sync, {"sync", OpType::System, 0, 3, 0, 0, 0}},
{982, Interpreter::icbi, {"icbi", OpType::System, FL_IN_A0B | FL_ENDBLOCK | FL_LOADSTORE, 4, 0, 0, 0}},
{4, Interpreter::tw}, // tw
{598, Interpreter::sync}, // sync
{982, Interpreter::icbi}, // icbi
// Unused instructions on GC
{310, Interpreter::eciwx, {"eciwx", OpType::System, FL_IN_A0B | FL_OUT_D | FL_LOADSTORE, 1, 0, 0, 0}},
{438, Interpreter::ecowx, {"ecowx", OpType::System, FL_IN_A0B | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}},
{854, Interpreter::eieio, {"eieio", OpType::System, 0, 1, 0, 0, 0}},
{306, Interpreter::tlbie, {"tlbie", OpType::System, FL_IN_B | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
{566, Interpreter::tlbsync, {"tlbsync", OpType::System, FL_PROGRAMEXCEPTION, 1, 0, 0, 0}},
// Unused instructions on GC
{310, Interpreter::eciwx}, // eciwx
{438, Interpreter::ecowx}, // ecowx
{854, Interpreter::eieio}, // eieio
{306, Interpreter::tlbie}, // tlbie
{566, Interpreter::tlbsync}, // tlbsync
}};
static std::array<GekkoOPTemplate, 9> table59 =
{{
{18, Interpreter::fdivsx, {"fdivsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 17, 0, 0, 0}}, // TODO
{20, Interpreter::fsubsx, {"fsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{21, Interpreter::faddsx, {"faddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{24, Interpreter::fresx, {"fresx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 1, 0, 0, 0}},
{25, Interpreter::fmulsx, {"fmulsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{28, Interpreter::fmsubsx, {"fmsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{29, Interpreter::fmaddsx, {"fmaddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{30, Interpreter::fnmsubsx, {"fnmsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{31, Interpreter::fnmaddsx, {"fnmaddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
constexpr std::array<InterpreterOpTemplate, 9> s_table59{{
{18, Interpreter::fdivsx}, // fdivsx // TODO
{20, Interpreter::fsubsx}, // fsubsx
{21, Interpreter::faddsx}, // faddsx
{24, Interpreter::fresx}, // fresx
{25, Interpreter::fmulsx}, // fmulsx
{28, Interpreter::fmsubsx}, // fmsubsx
{29, Interpreter::fmaddsx}, // fmaddsx
{30, Interpreter::fnmsubsx}, // fnmsubsx
{31, Interpreter::fnmaddsx}, // fnmaddsx
}};
static std::array<GekkoOPTemplate, 15> table63 =
{{
{264, Interpreter::fabsx, {"fabsx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU, 1, 0, 0, 0}},
constexpr std::array<InterpreterOpTemplate, 15> s_table63{{
{264, Interpreter::fabsx}, // fabsx
{32, Interpreter::fcmpo}, // fcmpo
{0, Interpreter::fcmpu}, // fcmpu
{14, Interpreter::fctiwx}, // fctiwx
{15, Interpreter::fctiwzx}, // fctiwzx
{72, Interpreter::fmrx}, // fmrx
{136, Interpreter::fnabsx}, // fnabsx
{40, Interpreter::fnegx}, // fnegx
{12, Interpreter::frspx}, // frspx
// FIXME: fcmp modifies the FPRF flags, but if the flags are clobbered later,
// we don't actually need to calculate or store them here. So FL_READ_FPRF and FL_SET_FPRF is not
// an ideal representation of fcmp's effect on FPRF flags and might result in
// slightly sub-optimal code.
{32, Interpreter::fcmpo, {"fcmpo", OpType::DoubleFP, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{0, Interpreter::fcmpu, {"fcmpu", OpType::DoubleFP, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{14, Interpreter::fctiwx, {"fctiwx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{15, Interpreter::fctiwzx, {"fctiwzx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{72, Interpreter::fmrx, {"fmrx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU, 1, 0, 0, 0}},
{136, Interpreter::fnabsx, {"fnabsx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_IN_FLOAT_B_BITEXACT | FL_USE_FPU, 1, 0, 0, 0}},
{40, Interpreter::fnegx, {"fnegx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_IN_FLOAT_B_BITEXACT | FL_USE_FPU, 1, 0, 0, 0}},
{12, Interpreter::frspx, {"frspx", OpType::DoubleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{64, Interpreter::mcrfs, {"mcrfs", OpType::SystemFP, FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF, 1, 0, 0, 0}},
{583, Interpreter::mffsx, {"mffsx", OpType::SystemFP, FL_RC_BIT_F | FL_INOUT_FLOAT_D | FL_USE_FPU | FL_READ_FPRF, 1, 0, 0, 0}},
{70, Interpreter::mtfsb0x, {"mtfsb0x", OpType::SystemFP, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF, 3, 0, 0, 0}},
{38, Interpreter::mtfsb1x, {"mtfsb1x", OpType::SystemFP, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 3, 0, 0, 0}},
{134, Interpreter::mtfsfix, {"mtfsfix", OpType::SystemFP, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 3, 0, 0, 0}},
{711, Interpreter::mtfsfx, {"mtfsfx", OpType::SystemFP, FL_RC_BIT_F | FL_IN_FLOAT_B | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 3, 0, 0, 0}},
{64, Interpreter::mcrfs}, // mcrfs
{583, Interpreter::mffsx}, // mffsx
{70, Interpreter::mtfsb0x}, // mtfsb0x
{38, Interpreter::mtfsb1x}, // mtfsb1x
{134, Interpreter::mtfsfix}, // mtfsfix
{711, Interpreter::mtfsfx}, // mtfsfx
}};
static std::array<GekkoOPTemplate, 10> table63_2 =
{{
{18, Interpreter::fdivx, {"fdivx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 31, 0, 0, 0}},
{20, Interpreter::fsubx, {"fsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{21, Interpreter::faddx, {"faddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{23, Interpreter::fselx, {"fselx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_IN_FLOAT_BC_BITEXACT | FL_RC_BIT_F | FL_USE_FPU, 1, 0, 0, 0}},
{25, Interpreter::fmulx, {"fmulx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{26, Interpreter::frsqrtex, {"frsqrtex", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 1, 0, 0, 0}},
{28, Interpreter::fmsubx, {"fmsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{29, Interpreter::fmaddx, {"fmaddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{30, Interpreter::fnmsubx, {"fnmsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
{31, Interpreter::fnmaddx, {"fnmaddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}},
constexpr std::array<InterpreterOpTemplate, 10> s_table63_2{{
{18, Interpreter::fdivx}, // fdivx
{20, Interpreter::fsubx}, // fsubx
{21, Interpreter::faddx}, // faddx
{23, Interpreter::fselx}, // fselx
{25, Interpreter::fmulx}, // fmulx
{26, Interpreter::frsqrtex}, // frsqrtex
{28, Interpreter::fmsubx}, // fmsubx
{29, Interpreter::fmaddx}, // fmaddx
{30, Interpreter::fnmsubx}, // fnmsubx
{31, Interpreter::fnmaddx}, // fnmaddx
}};
// clang-format on
constexpr size_t TotalInstructionFunctionCount()
constexpr std::array<Interpreter::Instruction, 64> s_interpreter_op_table = []() consteval
{
return primarytable.size() + table4_2.size() + table4_3.size() + table4.size() + table31.size() +
table19.size() + table59.size() + table63.size() + table63_2.size();
std::array<Interpreter::Instruction, 64> table{};
Common::Fill(table, Interpreter::unknown_instruction);
for (auto& tpl : s_primary_table)
{
ASSERT(table[tpl.opcode] == Interpreter::unknown_instruction);
table[tpl.opcode] = tpl.fn;
};
return table;
}
();
constexpr std::array<Interpreter::Instruction, 1024> s_interpreter_op_table4 = []() consteval
{
std::array<Interpreter::Instruction, 1024> table{};
Common::Fill(table, Interpreter::unknown_instruction);
for (u32 i = 0; i < 32; i++)
{
const u32 fill = i << 5;
for (const auto& tpl : s_table4_2)
{
const u32 op = fill + tpl.opcode;
ASSERT(table[op] == Interpreter::unknown_instruction);
table[op] = tpl.fn;
}
}
for (u32 i = 0; i < 16; i++)
{
const u32 fill = i << 6;
for (const auto& tpl : s_table4_3)
{
const u32 op = fill + tpl.opcode;
ASSERT(table[op] == Interpreter::unknown_instruction);
table[op] = tpl.fn;
}
}
for (const auto& tpl : s_table4)
{
const u32 op = tpl.opcode;
ASSERT(table[op] == Interpreter::unknown_instruction);
table[op] = tpl.fn;
}
return table;
}
();
constexpr std::array<Interpreter::Instruction, 1024> s_interpreter_op_table19 = []() consteval
{
std::array<Interpreter::Instruction, 1024> table{};
Common::Fill(table, Interpreter::unknown_instruction);
for (auto& tpl : s_table19)
{
ASSERT(table[tpl.opcode] == Interpreter::unknown_instruction);
table[tpl.opcode] = tpl.fn;
};
return table;
}
();
constexpr std::array<Interpreter::Instruction, 1024> s_interpreter_op_table31 = []() consteval
{
std::array<Interpreter::Instruction, 1024> table{};
Common::Fill(table, Interpreter::unknown_instruction);
for (auto& tpl : s_table31)
{
ASSERT(table[tpl.opcode] == Interpreter::unknown_instruction);
table[tpl.opcode] = tpl.fn;
};
return table;
}
();
constexpr std::array<Interpreter::Instruction, 32> s_interpreter_op_table59 = []() consteval
{
std::array<Interpreter::Instruction, 32> table{};
Common::Fill(table, Interpreter::unknown_instruction);
for (auto& tpl : s_table59)
{
ASSERT(table[tpl.opcode] == Interpreter::unknown_instruction);
table[tpl.opcode] = tpl.fn;
};
return table;
}
();
constexpr std::array<Interpreter::Instruction, 1024> s_interpreter_op_table63 = []() consteval
{
std::array<Interpreter::Instruction, 1024> table{};
Common::Fill(table, Interpreter::unknown_instruction);
for (auto& tpl : s_table63)
{
ASSERT(table[tpl.opcode] == Interpreter::unknown_instruction);
table[tpl.opcode] = tpl.fn;
};
for (u32 i = 0; i < 32; i++)
{
const u32 fill = i << 5;
for (const auto& tpl : s_table63_2)
{
const u32 op = fill + tpl.opcode;
ASSERT(table[op] == Interpreter::unknown_instruction);
table[op] = tpl.fn;
}
}
return table;
}
();
Interpreter::Instruction Interpreter::GetInterpreterOp(UGeckoInstruction inst)
{
// Check for the appropriate subtable ahead of time.
// (This is used by the cached interpreter and JIT, and called once per instruction, so spending a
// bit of extra time to optimise is worthwhile)
Interpreter::Instruction result = s_interpreter_op_table[inst.OPCD];
if (result == Interpreter::RunTable4)
return s_interpreter_op_table4[inst.SUBOP10];
else if (result == Interpreter::RunTable19)
return s_interpreter_op_table19[inst.SUBOP10];
else if (result == Interpreter::RunTable31)
return s_interpreter_op_table31[inst.SUBOP10];
else if (result == Interpreter::RunTable59)
return s_interpreter_op_table59[inst.SUBOP5];
else if (result == Interpreter::RunTable63)
return s_interpreter_op_table63[inst.SUBOP10];
else
return result;
}
static_assert(TotalInstructionFunctionCount() < m_allInstructions.size(),
"m_allInstructions is too small");
void Interpreter::InitializeInstructionTables()
void Interpreter::RunInterpreterOp(UGeckoInstruction inst)
{
// once initialized, tables are read-only
static bool initialized = false;
if (initialized)
return;
// clear
for (int i = 0; i < 64; i++)
{
m_op_table[i] = Interpreter::unknown_instruction;
m_infoTable[i] = &unknownopinfo;
}
for (int i = 0; i < 32; i++)
{
m_op_table59[i] = Interpreter::unknown_instruction;
m_infoTable59[i] = &unknownopinfo;
}
for (int i = 0; i < 1024; i++)
{
m_op_table4[i] = Interpreter::unknown_instruction;
m_op_table19[i] = Interpreter::unknown_instruction;
m_op_table31[i] = Interpreter::unknown_instruction;
m_op_table63[i] = Interpreter::unknown_instruction;
m_infoTable4[i] = &unknownopinfo;
m_infoTable19[i] = &unknownopinfo;
m_infoTable31[i] = &unknownopinfo;
m_infoTable63[i] = &unknownopinfo;
}
for (auto& tpl : primarytable)
{
m_op_table[tpl.opcode] = tpl.Inst;
m_infoTable[tpl.opcode] = &tpl.opinfo;
}
for (int i = 0; i < 32; i++)
{
int fill = i << 5;
for (auto& tpl : table4_2)
{
int op = fill + tpl.opcode;
m_op_table4[op] = tpl.Inst;
m_infoTable4[op] = &tpl.opinfo;
}
}
for (int i = 0; i < 16; i++)
{
int fill = i << 6;
for (auto& tpl : table4_3)
{
int op = fill + tpl.opcode;
m_op_table4[op] = tpl.Inst;
m_infoTable4[op] = &tpl.opinfo;
}
}
for (auto& tpl : table4)
{
int op = tpl.opcode;
m_op_table4[op] = tpl.Inst;
m_infoTable4[op] = &tpl.opinfo;
}
for (auto& tpl : table31)
{
int op = tpl.opcode;
m_op_table31[op] = tpl.Inst;
m_infoTable31[op] = &tpl.opinfo;
}
for (auto& tpl : table19)
{
int op = tpl.opcode;
m_op_table19[op] = tpl.Inst;
m_infoTable19[op] = &tpl.opinfo;
}
for (auto& tpl : table59)
{
int op = tpl.opcode;
m_op_table59[op] = tpl.Inst;
m_infoTable59[op] = &tpl.opinfo;
}
for (auto& tpl : table63)
{
int op = tpl.opcode;
m_op_table63[op] = tpl.Inst;
m_infoTable63[op] = &tpl.opinfo;
}
for (int i = 0; i < 32; i++)
{
int fill = i << 5;
for (auto& tpl : table63_2)
{
int op = fill + tpl.opcode;
m_op_table63[op] = tpl.Inst;
m_infoTable63[op] = &tpl.opinfo;
}
}
m_numInstructions = 0;
for (auto& tpl : primarytable)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table4_2)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table4_3)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table4)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table31)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table19)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table59)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table63)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table63_2)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
initialized = true;
// Will handle subtables using RunTable4 etc.
s_interpreter_op_table[inst.OPCD](inst);
}
void Interpreter::RunTable4(UGeckoInstruction inst)
{
s_interpreter_op_table4[inst.SUBOP10](inst);
}
void Interpreter::RunTable19(UGeckoInstruction inst)
{
s_interpreter_op_table19[inst.SUBOP10](inst);
}
void Interpreter::RunTable31(UGeckoInstruction inst)
{
s_interpreter_op_table31[inst.SUBOP10](inst);
}
void Interpreter::RunTable59(UGeckoInstruction inst)
{
s_interpreter_op_table59[inst.SUBOP5](inst);
}
void Interpreter::RunTable63(UGeckoInstruction inst)
{
s_interpreter_op_table63[inst.SUBOP10](inst);
}

View file

@ -342,7 +342,7 @@ void Jit64::FallBackToInterpreter(UGeckoInstruction inst)
MOV(32, PPCSTATE(npc), Imm32(js.compilerPC + 4));
}
Interpreter::Instruction instr = PPCTables::GetInterpreterOp(inst);
Interpreter::Instruction instr = Interpreter::GetInterpreterOp(inst);
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionC(instr, inst.hex);
ABI_PopRegistersAndAdjustStack({}, 0);
@ -921,7 +921,7 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
js.instructionNumber = i;
js.instructionsLeft = (code_block.m_num_instructions - 1) - i;
const GekkoOPInfo* opinfo = op.opinfo;
js.downcountAmount += opinfo->numCycles;
js.downcountAmount += opinfo->num_cycles;
js.fastmemLoadStore = nullptr;
js.fixupExceptionHandler = false;

View file

@ -5,17 +5,19 @@
#include <array>
#include "Common/Assert.h"
#include "Common/TypeUtils.h"
#include "Core/PowerPC/Gekko.h"
namespace
{
struct GekkoOPTemplate
struct Jit64OpTemplate
{
u32 opcode;
Jit64::Instruction fn;
};
constexpr std::array<GekkoOPTemplate, 54> s_primary_table{{
constexpr std::array<Jit64OpTemplate, 54> s_primary_table{{
{4, &Jit64::DynaRunTable4}, // RunTable4
{19, &Jit64::DynaRunTable19}, // RunTable19
{31, &Jit64::DynaRunTable31}, // RunTable31
@ -85,7 +87,7 @@ constexpr std::array<GekkoOPTemplate, 54> s_primary_table{{
// missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58
}};
constexpr std::array<GekkoOPTemplate, 13> s_table4{{
constexpr std::array<Jit64OpTemplate, 13> s_table4{{
// SUBOP10
{0, &Jit64::ps_cmpXX}, // ps_cmpu0
{32, &Jit64::ps_cmpXX}, // ps_cmpo0
@ -103,7 +105,7 @@ constexpr std::array<GekkoOPTemplate, 13> s_table4{{
{1014, &Jit64::FallBackToInterpreter}, // dcbz_l
}};
constexpr std::array<GekkoOPTemplate, 17> s_table4_2{{
constexpr std::array<Jit64OpTemplate, 17> s_table4_2{{
{10, &Jit64::ps_sum}, // ps_sum0
{11, &Jit64::ps_sum}, // ps_sum1
{12, &Jit64::ps_muls}, // ps_muls0
@ -123,14 +125,14 @@ constexpr std::array<GekkoOPTemplate, 17> s_table4_2{{
{31, &Jit64::fmaddXX}, // ps_nmadd
}};
constexpr std::array<GekkoOPTemplate, 4> s_table4_3{{
constexpr std::array<Jit64OpTemplate, 4> s_table4_3{{
{6, &Jit64::psq_lXX}, // psq_lx
{7, &Jit64::psq_stXX}, // psq_stx
{38, &Jit64::psq_lXX}, // psq_lux
{39, &Jit64::psq_stXX}, // psq_stux
}};
constexpr std::array<GekkoOPTemplate, 13> s_table19{{
constexpr std::array<Jit64OpTemplate, 13> s_table19{{
{528, &Jit64::bcctrx}, // bcctrx
{16, &Jit64::bclrx}, // bclrx
{257, &Jit64::crXXX}, // crand
@ -148,7 +150,7 @@ constexpr std::array<GekkoOPTemplate, 13> s_table19{{
{50, &Jit64::rfi}, // rfi
}};
constexpr std::array<GekkoOPTemplate, 107> s_table31{{
constexpr std::array<Jit64OpTemplate, 107> s_table31{{
{266, &Jit64::addx}, // addx
{778, &Jit64::addx}, // addox
{10, &Jit64::addx}, // addcx
@ -290,7 +292,7 @@ constexpr std::array<GekkoOPTemplate, 107> s_table31{{
{566, &Jit64::DoNothing}, // tlbsync
}};
constexpr std::array<GekkoOPTemplate, 9> s_table59{{
constexpr std::array<Jit64OpTemplate, 9> s_table59{{
{18, &Jit64::fp_arith}, // fdivsx
{20, &Jit64::fp_arith}, // fsubsx
{21, &Jit64::fp_arith}, // faddsx
@ -302,7 +304,7 @@ constexpr std::array<GekkoOPTemplate, 9> s_table59{{
{31, &Jit64::fmaddXX}, // fnmaddsx
}};
constexpr std::array<GekkoOPTemplate, 15> s_table63{{
constexpr std::array<Jit64OpTemplate, 15> s_table63{{
{264, &Jit64::fsign}, // fabsx
{32, &Jit64::fcmpX}, // fcmpo
{0, &Jit64::fcmpX}, // fcmpu
@ -321,7 +323,7 @@ constexpr std::array<GekkoOPTemplate, 15> s_table63{{
{711, &Jit64::mtfsfx}, // mtfsfx
}};
constexpr std::array<GekkoOPTemplate, 10> s_table63_2{{
constexpr std::array<Jit64OpTemplate, 10> s_table63_2{{
{18, &Jit64::fp_arith}, // fdivx
{20, &Jit64::fp_arith}, // fsubx
{21, &Jit64::fp_arith}, // faddx
@ -334,38 +336,25 @@ constexpr std::array<GekkoOPTemplate, 10> s_table63_2{{
{31, &Jit64::fmaddXX}, // fnmaddx
}};
// TODO: This can be replaced with:
//
// table.fill(&Jit64::FallbackToInterpreter);
//
// whenever we end up migrating to C++20. Prior to C++20,
// std::array's fill() function is, unfortunately, not constexpr.
// Ditto for <algorithm>'s std::fill. Thus, this function exists
// to bridge the gap.
template <size_t N>
constexpr void FillWithFallbacks(std::array<Jit64::Instruction, N>& table)
constexpr std::array<Jit64::Instruction, 64> s_dyna_op_table = []() consteval
{
for (auto& entry : table)
{
entry = &Jit64::FallBackToInterpreter;
}
}
constexpr std::array<Jit64::Instruction, 64> s_dyna_op_table = [] {
std::array<Jit64::Instruction, 64> table{};
FillWithFallbacks(table);
Common::Fill(table, &Jit64::FallBackToInterpreter);
for (auto& tpl : s_primary_table)
{
ASSERT(table[tpl.opcode] == &Jit64::FallBackToInterpreter);
table[tpl.opcode] = tpl.fn;
}
return table;
}();
}
();
constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table4 = [] {
constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table4 = []() consteval
{
std::array<Jit64::Instruction, 1024> table{};
FillWithFallbacks(table);
Common::Fill(table, &Jit64::FallBackToInterpreter);
for (u32 i = 0; i < 32; i++)
{
@ -373,6 +362,7 @@ constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table4 = [] {
for (const auto& tpl : s_table4_2)
{
const u32 op = fill + tpl.opcode;
ASSERT(table[op] == &Jit64::FallBackToInterpreter);
table[op] = tpl.fn;
}
}
@ -383,6 +373,7 @@ constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table4 = [] {
for (const auto& tpl : s_table4_3)
{
const u32 op = fill + tpl.opcode;
ASSERT(table[op] == &Jit64::FallBackToInterpreter);
table[op] = tpl.fn;
}
}
@ -390,59 +381,68 @@ constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table4 = [] {
for (const auto& tpl : s_table4)
{
const u32 op = tpl.opcode;
ASSERT(table[op] == &Jit64::FallBackToInterpreter);
table[op] = tpl.fn;
}
return table;
}();
}
();
constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table19 = [] {
constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table19 = []() consteval
{
std::array<Jit64::Instruction, 1024> table{};
FillWithFallbacks(table);
Common::Fill(table, &Jit64::FallBackToInterpreter);
for (const auto& tpl : s_table19)
{
const u32 op = tpl.opcode;
table[op] = tpl.fn;
ASSERT(table[tpl.opcode] == &Jit64::FallBackToInterpreter);
table[tpl.opcode] = tpl.fn;
}
return table;
}();
}
();
constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table31 = [] {
constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table31 = []() consteval
{
std::array<Jit64::Instruction, 1024> table{};
FillWithFallbacks(table);
Common::Fill(table, &Jit64::FallBackToInterpreter);
for (const auto& tpl : s_table31)
{
const u32 op = tpl.opcode;
table[op] = tpl.fn;
ASSERT(table[tpl.opcode] == &Jit64::FallBackToInterpreter);
table[tpl.opcode] = tpl.fn;
}
return table;
}();
}
();
constexpr std::array<Jit64::Instruction, 32> s_dyna_op_table59 = [] {
constexpr std::array<Jit64::Instruction, 32> s_dyna_op_table59 = []() consteval
{
std::array<Jit64::Instruction, 32> table{};
FillWithFallbacks(table);
Common::Fill(table, &Jit64::FallBackToInterpreter);
for (const auto& tpl : s_table59)
{
const u32 op = tpl.opcode;
table[op] = tpl.fn;
ASSERT(table[tpl.opcode] == &Jit64::FallBackToInterpreter);
table[tpl.opcode] = tpl.fn;
}
return table;
}();
}
();
constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table63 = [] {
constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table63 = []() consteval
{
std::array<Jit64::Instruction, 1024> table{};
FillWithFallbacks(table);
Common::Fill(table, &Jit64::FallBackToInterpreter);
for (const auto& tpl : s_table63)
{
const u32 op = tpl.opcode;
table[op] = tpl.fn;
ASSERT(table[tpl.opcode] == &Jit64::FallBackToInterpreter);
table[tpl.opcode] = tpl.fn;
}
for (u32 i = 0; i < 32; i++)
@ -451,12 +451,14 @@ constexpr std::array<Jit64::Instruction, 1024> s_dyna_op_table63 = [] {
for (const auto& tpl : s_table63_2)
{
const u32 op = fill + tpl.opcode;
ASSERT(table[op] == &Jit64::FallBackToInterpreter);
table[op] = tpl.fn;
}
}
return table;
}();
}
();
} // Anonymous namespace
@ -489,16 +491,5 @@ void Jit64::CompileInstruction(PPCAnalyst::CodeOp& op)
{
(this->*s_dyna_op_table[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;
}
PPCTables::CountInstructionCompile(op.opinfo, js.compilerPC);
}

View file

@ -267,7 +267,7 @@ void Jit64::dcbx(UGeckoInstruction inst)
// Alright, now figure out how many loops we want to do.
const u8 cycle_count_per_loop =
js.op[0].opinfo->numCycles + js.op[1].opinfo->numCycles + js.op[2].opinfo->numCycles;
js.op[0].opinfo->num_cycles + js.op[1].opinfo->num_cycles + js.op[2].opinfo->num_cycles;
// This is both setting the adjusted loop count to 0 for the downcount <= 0 case and clearing
// the upper bits for the DIV instruction in the downcount > 0 case.

View file

@ -197,7 +197,7 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
gpr.Unlock(WA);
}
Interpreter::Instruction instr = PPCTables::GetInterpreterOp(inst);
Interpreter::Instruction instr = Interpreter::GetInterpreterOp(inst);
MOVP2R(ARM64Reg::X8, instr);
MOVI2R(ARM64Reg::W0, inst.hex);
BLR(ARM64Reg::X8);
@ -903,7 +903,7 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
js.instructionNumber = i;
js.instructionsLeft = (code_block.m_num_instructions - 1) - i;
const GekkoOPInfo* opinfo = op.opinfo;
js.downcountAmount += opinfo->numCycles;
js.downcountAmount += opinfo->num_cycles;
js.isLastInstruction = i == (code_block.m_num_instructions - 1);
if (!m_enable_debugging)

View file

@ -677,7 +677,7 @@ void JitArm64::dcbx(UGeckoInstruction inst)
// Figure out how many loops we want to do.
const u8 cycle_count_per_loop =
js.op[0].opinfo->numCycles + js.op[1].opinfo->numCycles + js.op[2].opinfo->numCycles;
js.op[0].opinfo->num_cycles + js.op[1].opinfo->num_cycles + js.op[2].opinfo->num_cycles;
LDR(IndexType::Unsigned, reg_downcount, PPC_REG, PPCSTATE_OFF(downcount));
MOVI2R(WA, 0);

View file

@ -5,19 +5,19 @@
#include <array>
#include "Common/Assert.h"
#include "Common/TypeUtils.h"
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/PPCTables.h"
namespace
{
struct GekkoOPTemplate
struct JitArm64OpTemplate
{
int opcode;
u32 opcode;
JitArm64::Instruction fn;
// GekkoOPInfo opinfo; // Doesn't need opinfo, Interpreter fills it out
};
constexpr std::array<GekkoOPTemplate, 54> primarytable{{
constexpr std::array<JitArm64OpTemplate, 54> s_primary_table{{
{4, &JitArm64::DynaRunTable4}, // RunTable4
{19, &JitArm64::DynaRunTable19}, // RunTable19
{31, &JitArm64::DynaRunTable31}, // RunTable31
@ -87,7 +87,7 @@ constexpr std::array<GekkoOPTemplate, 54> primarytable{{
// missing: 0, 1, 2, 5, 6, 9, 22, 30, 58, 62
}};
constexpr std::array<GekkoOPTemplate, 13> table4{{
constexpr std::array<JitArm64OpTemplate, 13> s_table4{{
// SUBOP10
{0, &JitArm64::ps_cmpXX}, // ps_cmpu0
{32, &JitArm64::ps_cmpXX}, // ps_cmpo0
@ -105,7 +105,7 @@ constexpr std::array<GekkoOPTemplate, 13> table4{{
{1014, &JitArm64::FallBackToInterpreter}, // dcbz_l
}};
constexpr std::array<GekkoOPTemplate, 17> table4_2{{
constexpr std::array<JitArm64OpTemplate, 17> s_table4_2{{
{10, &JitArm64::ps_sumX}, // ps_sum0
{11, &JitArm64::ps_sumX}, // ps_sum1
{12, &JitArm64::ps_arith}, // ps_muls0
@ -125,14 +125,14 @@ constexpr std::array<GekkoOPTemplate, 17> table4_2{{
{31, &JitArm64::ps_arith}, // ps_nmadd
}};
constexpr std::array<GekkoOPTemplate, 4> table4_3{{
constexpr std::array<JitArm64OpTemplate, 4> s_table4_3{{
{6, &JitArm64::psq_lXX}, // psq_lx
{7, &JitArm64::psq_stXX}, // psq_stx
{38, &JitArm64::psq_lXX}, // psq_lux
{39, &JitArm64::psq_stXX}, // psq_stux
}};
constexpr std::array<GekkoOPTemplate, 13> table19{{
constexpr std::array<JitArm64OpTemplate, 13> s_table19{{
{528, &JitArm64::bcctrx}, // bcctrx
{16, &JitArm64::bclrx}, // bclrx
{257, &JitArm64::crXXX}, // crand
@ -150,7 +150,7 @@ constexpr std::array<GekkoOPTemplate, 13> table19{{
{50, &JitArm64::rfi}, // rfi
}};
constexpr std::array<GekkoOPTemplate, 107> table31{{
constexpr std::array<JitArm64OpTemplate, 107> s_table31{{
{266, &JitArm64::addx}, // addx
{778, &JitArm64::addx}, // addox
{10, &JitArm64::addcx}, // addcx
@ -292,7 +292,7 @@ constexpr std::array<GekkoOPTemplate, 107> table31{{
{566, &JitArm64::DoNothing}, // tlbsync
}};
constexpr std::array<GekkoOPTemplate, 9> table59{{
constexpr std::array<JitArm64OpTemplate, 9> s_table59{{
{18, &JitArm64::fp_arith}, // fdivsx
{20, &JitArm64::fp_arith}, // fsubsx
{21, &JitArm64::fp_arith}, // faddsx
@ -304,7 +304,7 @@ constexpr std::array<GekkoOPTemplate, 9> table59{{
{31, &JitArm64::fp_arith}, // fnmaddsx
}};
constexpr std::array<GekkoOPTemplate, 15> table63{{
constexpr std::array<JitArm64OpTemplate, 15> s_table63{{
{264, &JitArm64::fp_logic}, // fabsx
{32, &JitArm64::fcmpX}, // fcmpo
{0, &JitArm64::fcmpX}, // fcmpu
@ -323,7 +323,7 @@ constexpr std::array<GekkoOPTemplate, 15> table63{{
{711, &JitArm64::mtfsfx}, // mtfsfx
}};
constexpr std::array<GekkoOPTemplate, 10> table63_2{{
constexpr std::array<JitArm64OpTemplate, 10> s_table63_2{{
{18, &JitArm64::fp_arith}, // fdivx
{20, &JitArm64::fp_arith}, // fsubx
{21, &JitArm64::fp_arith}, // faddx
@ -336,172 +336,160 @@ constexpr std::array<GekkoOPTemplate, 10> table63_2{{
{31, &JitArm64::fp_arith}, // fnmaddx
}};
constexpr std::array<JitArm64::Instruction, 64> dynaOpTable = [] {
constexpr std::array<JitArm64::Instruction, 64> s_dyna_op_table = []() consteval
{
std::array<JitArm64::Instruction, 64> table{};
Common::Fill(table, &JitArm64::FallBackToInterpreter);
for (auto& tpl : table)
{
tpl = &JitArm64::FallBackToInterpreter;
}
for (const auto& tpl : primarytable)
for (auto& tpl : s_primary_table)
{
ASSERT(table[tpl.opcode] == &JitArm64::FallBackToInterpreter);
table[tpl.opcode] = tpl.fn;
}
return table;
}();
}
();
constexpr std::array<JitArm64::Instruction, 1024> dynaOpTable4 = [] {
constexpr std::array<JitArm64::Instruction, 1024> s_dyna_op_table4 = []() consteval
{
std::array<JitArm64::Instruction, 1024> table{};
Common::Fill(table, &JitArm64::FallBackToInterpreter);
for (auto& entry : table)
for (u32 i = 0; i < 32; i++)
{
entry = &JitArm64::FallBackToInterpreter;
}
for (int i = 0; i < 32; i++)
{
const int fill = i << 5;
for (const auto& tpl : table4_2)
const u32 fill = i << 5;
for (const auto& tpl : s_table4_2)
{
const int op = fill + tpl.opcode;
const u32 op = fill + tpl.opcode;
ASSERT(table[op] == &JitArm64::FallBackToInterpreter);
table[op] = tpl.fn;
}
}
for (int i = 0; i < 16; i++)
for (u32 i = 0; i < 16; i++)
{
const int fill = i << 6;
for (const auto& tpl : table4_3)
const u32 fill = i << 6;
for (const auto& tpl : s_table4_3)
{
const int op = fill + tpl.opcode;
const u32 op = fill + tpl.opcode;
ASSERT(table[op] == &JitArm64::FallBackToInterpreter);
table[op] = tpl.fn;
}
}
for (const auto& tpl : table4)
for (const auto& tpl : s_table4)
{
table[tpl.opcode] = tpl.fn;
const u32 op = tpl.opcode;
ASSERT(table[op] == &JitArm64::FallBackToInterpreter);
table[op] = tpl.fn;
}
return table;
}();
}
();
constexpr std::array<JitArm64::Instruction, 1024> dynaOpTable19 = [] {
constexpr std::array<JitArm64::Instruction, 1024> s_dyna_op_table19 = []() consteval
{
std::array<JitArm64::Instruction, 1024> table{};
Common::Fill(table, &JitArm64::FallBackToInterpreter);
for (auto& entry : table)
{
entry = &JitArm64::FallBackToInterpreter;
}
for (const auto& tpl : table19)
for (const auto& tpl : s_table19)
{
ASSERT(table[tpl.opcode] == &JitArm64::FallBackToInterpreter);
table[tpl.opcode] = tpl.fn;
}
return table;
}();
}
();
constexpr std::array<JitArm64::Instruction, 1024> dynaOpTable31 = [] {
constexpr std::array<JitArm64::Instruction, 1024> s_dyna_op_table31 = []() consteval
{
std::array<JitArm64::Instruction, 1024> table{};
Common::Fill(table, &JitArm64::FallBackToInterpreter);
for (auto& entry : table)
{
entry = &JitArm64::FallBackToInterpreter;
}
for (const auto& tpl : table31)
for (const auto& tpl : s_table31)
{
ASSERT(table[tpl.opcode] == &JitArm64::FallBackToInterpreter);
table[tpl.opcode] = tpl.fn;
}
return table;
}();
}
();
constexpr std::array<JitArm64::Instruction, 32> dynaOpTable59 = [] {
constexpr std::array<JitArm64::Instruction, 32> s_dyna_op_table59 = []() consteval
{
std::array<JitArm64::Instruction, 32> table{};
Common::Fill(table, &JitArm64::FallBackToInterpreter);
for (auto& entry : table)
{
entry = &JitArm64::FallBackToInterpreter;
}
for (const auto& tpl : table59)
for (const auto& tpl : s_table59)
{
ASSERT(table[tpl.opcode] == &JitArm64::FallBackToInterpreter);
table[tpl.opcode] = tpl.fn;
}
return table;
}();
}
();
constexpr std::array<JitArm64::Instruction, 1024> dynaOpTable63 = [] {
constexpr std::array<JitArm64::Instruction, 1024> s_dyna_op_table63 = []() consteval
{
std::array<JitArm64::Instruction, 1024> table{};
Common::Fill(table, &JitArm64::FallBackToInterpreter);
for (auto& entry : table)
{
entry = &JitArm64::FallBackToInterpreter;
}
for (const auto& tpl : table63)
for (const auto& tpl : s_table63)
{
ASSERT(table[tpl.opcode] == &JitArm64::FallBackToInterpreter);
table[tpl.opcode] = tpl.fn;
}
for (int i = 0; i < 32; i++)
for (u32 i = 0; i < 32; i++)
{
const int fill = i << 5;
for (const auto& tpl : table63_2)
const u32 fill = i << 5;
for (const auto& tpl : s_table63_2)
{
const int op = fill + tpl.opcode;
const u32 op = fill + tpl.opcode;
ASSERT(table[op] == &JitArm64::FallBackToInterpreter);
table[op] = tpl.fn;
}
}
return table;
}();
}
();
} // Anonymous namespace
void JitArm64::DynaRunTable4(UGeckoInstruction inst)
{
(this->*dynaOpTable4[inst.SUBOP10])(inst);
(this->*s_dyna_op_table4[inst.SUBOP10])(inst);
}
void JitArm64::DynaRunTable19(UGeckoInstruction inst)
{
(this->*dynaOpTable19[inst.SUBOP10])(inst);
(this->*s_dyna_op_table19[inst.SUBOP10])(inst);
}
void JitArm64::DynaRunTable31(UGeckoInstruction inst)
{
(this->*dynaOpTable31[inst.SUBOP10])(inst);
(this->*s_dyna_op_table31[inst.SUBOP10])(inst);
}
void JitArm64::DynaRunTable59(UGeckoInstruction inst)
{
(this->*dynaOpTable59[inst.SUBOP5])(inst);
(this->*s_dyna_op_table59[inst.SUBOP5])(inst);
}
void JitArm64::DynaRunTable63(UGeckoInstruction inst)
{
(this->*dynaOpTable63[inst.SUBOP10])(inst);
(this->*s_dyna_op_table63[inst.SUBOP10])(inst);
}
void JitArm64::CompileInstruction(PPCAnalyst::CodeOp& op)
{
(this->*dynaOpTable[op.inst.OPCD])(op.inst);
(this->*s_dyna_op_table[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;
}
PPCTables::CountInstructionCompile(op.opinfo, js.compilerPC);
}

View file

@ -770,13 +770,13 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
num_inst++;
const UGeckoInstruction inst = result.hex;
GekkoOPInfo* opinfo = PPCTables::GetOpInfo(inst);
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(inst);
code[i] = {};
code[i].opinfo = opinfo;
code[i].address = address;
code[i].inst = inst;
code[i].skip = false;
block->m_stats->numCycles += opinfo->numCycles;
block->m_stats->numCycles += opinfo->num_cycles;
block->m_physical_addresses.insert(result.physical_address);
SetInstructionStats(block, &code[i], opinfo);

View file

@ -29,7 +29,7 @@ namespace PPCAnalyst
struct CodeOp // 16B
{
UGeckoInstruction inst;
GekkoOPInfo* opinfo = nullptr;
const GekkoOPInfo* opinfo = nullptr;
u32 address = 0;
u32 branchTo = 0; // if UINT32_MAX, not a branch
BitSet32 regsOut;

View file

@ -17,43 +17,623 @@
#include "Common/IOFile.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "Common/TypeUtils.h"
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/PowerPC.h"
std::array<GekkoOPInfo*, 64> m_infoTable;
std::array<GekkoOPInfo*, 1024> m_infoTable4;
std::array<GekkoOPInfo*, 1024> m_infoTable19;
std::array<GekkoOPInfo*, 1024> m_infoTable31;
std::array<GekkoOPInfo*, 32> m_infoTable59;
std::array<GekkoOPInfo*, 1024> m_infoTable63;
std::array<GekkoOPInfo*, 512> m_allInstructions;
size_t m_numInstructions;
namespace PPCTables
{
GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
namespace
{
const GekkoOPInfo* info = m_infoTable[inst.OPCD];
struct GekkoOPTemplate
{
u32 opcode;
const char* opname;
OpType type;
u32 num_cycles;
u64 flags;
};
constexpr GekkoOPTemplate s_unknown_op_info = {0, "unknown_instruction", OpType::Unknown, 0,
FL_ENDBLOCK};
constexpr std::array<GekkoOPTemplate, 54> s_primary_table{{
{4, "RunTable4", OpType::Subtable, 0, 0},
{19, "RunTable19", OpType::Subtable, 0, 0},
{31, "RunTable31", OpType::Subtable, 0, 0},
{59, "RunTable59", OpType::Subtable, 0, 0},
{63, "RunTable63", OpType::Subtable, 0, 0},
{16, "bcx", OpType::Branch, 1, FL_ENDBLOCK | FL_READ_CR_BI},
{18, "bx", OpType::Branch, 1, FL_ENDBLOCK},
{3, "twi", OpType::System, 1, FL_IN_A | FL_ENDBLOCK},
{17, "sc", OpType::System, 2, FL_ENDBLOCK},
{7, "mulli", OpType::Integer, 3, FL_OUT_D | FL_IN_A},
{8, "subfic", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_SET_CA},
{10, "cmpli", OpType::Integer, 1, FL_IN_A | FL_SET_CRn},
{11, "cmpi", OpType::Integer, 1, FL_IN_A | FL_SET_CRn},
{12, "addic", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_SET_CA},
{13, "addic_rc", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_SET_CA | FL_SET_CR0},
{14, "addi", OpType::Integer, 1, FL_OUT_D | FL_IN_A0},
{15, "addis", OpType::Integer, 1, FL_OUT_D | FL_IN_A0},
{20, "rlwimix", OpType::Integer, 1, FL_OUT_A | FL_IN_A | FL_IN_S | FL_RC_BIT},
{21, "rlwinmx", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_RC_BIT},
{23, "rlwnmx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT},
{24, "ori", OpType::Integer, 1, FL_OUT_A | FL_IN_S},
{25, "oris", OpType::Integer, 1, FL_OUT_A | FL_IN_S},
{26, "xori", OpType::Integer, 1, FL_OUT_A | FL_IN_S},
{27, "xoris", OpType::Integer, 1, FL_OUT_A | FL_IN_S},
{28, "andi_rc", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_SET_CR0},
{29, "andis_rc", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_SET_CR0},
{32, "lwz", OpType::Load, 1, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE},
{33, "lwzu", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE},
{34, "lbz", OpType::Load, 1, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE},
{35, "lbzu", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE},
{40, "lhz", OpType::Load, 1, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE},
{41, "lhzu", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE},
{42, "lha", OpType::Load, 1, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE},
{43, "lhau", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE},
{44, "sth", OpType::Store, 1, FL_IN_A0 | FL_IN_S | FL_LOADSTORE},
{45, "sthu", OpType::Store, 1, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE},
{36, "stw", OpType::Store, 1, FL_IN_A0 | FL_IN_S | FL_LOADSTORE},
{37, "stwu", OpType::Store, 1, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE},
{38, "stb", OpType::Store, 1, FL_IN_A0 | FL_IN_S | FL_LOADSTORE},
{39, "stbu", OpType::Store, 1, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE},
{46, "lmw", OpType::System, 11, FL_EVIL | FL_IN_A0 | FL_LOADSTORE},
{47, "stmw", OpType::System, 11, FL_EVIL | FL_IN_A0 | FL_LOADSTORE},
{48, "lfs", OpType::LoadFP, 1, FL_OUT_FLOAT_D | FL_IN_A | FL_USE_FPU | FL_LOADSTORE},
{49, "lfsu", OpType::LoadFP, 1,
FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE},
{50, "lfd", OpType::LoadFP, 1, FL_INOUT_FLOAT_D | FL_IN_A | FL_USE_FPU | FL_LOADSTORE},
{51, "lfdu", OpType::LoadFP, 1,
FL_INOUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE},
{52, "stfs", OpType::StoreFP, 1, FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE},
{53, "stfsu", OpType::StoreFP, 1,
FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE},
{54, "stfd", OpType::StoreFP, 1, FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE},
{55, "stfdu", OpType::StoreFP, 1,
FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE},
{56, "psq_l", OpType::LoadPS, 1,
FL_OUT_FLOAT_D | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION},
{57, "psq_lu", OpType::LoadPS, 1,
FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION},
{60, "psq_st", OpType::StorePS, 1,
FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION},
{61, "psq_stu", OpType::StorePS, 1,
FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION},
// missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58
}};
constexpr std::array<GekkoOPTemplate, 13> s_table4{{
// SUBOP10
{0, "ps_cmpu0", OpType::PS, 1,
FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION |
FL_FLOAT_EXCEPTION},
{32, "ps_cmpo0", OpType::PS, 1,
FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION |
FL_FLOAT_EXCEPTION},
{40, "ps_neg", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU |
FL_PROGRAMEXCEPTION},
{136, "ps_nabs", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU |
FL_PROGRAMEXCEPTION},
{264, "ps_abs", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU |
FL_PROGRAMEXCEPTION},
{64, "ps_cmpu1", OpType::PS, 1,
FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION |
FL_FLOAT_EXCEPTION},
{72, "ps_mr", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU |
FL_PROGRAMEXCEPTION},
{96, "ps_cmpo1", OpType::PS, 1,
FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION |
FL_FLOAT_EXCEPTION},
{528, "ps_merge00", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU |
FL_PROGRAMEXCEPTION},
{560, "ps_merge01", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU |
FL_PROGRAMEXCEPTION},
{592, "ps_merge10", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU |
FL_PROGRAMEXCEPTION},
{624, "ps_merge11", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU |
FL_PROGRAMEXCEPTION},
{1014, "dcbz_l", OpType::System, 1, FL_IN_A0B | FL_LOADSTORE | FL_PROGRAMEXCEPTION},
}};
constexpr std::array<GekkoOPTemplate, 17> s_table4_2{{
{10, "ps_sum0", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{11, "ps_sum1", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{12, "ps_muls0", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{13, "ps_muls1", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{14, "ps_madds0", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{15, "ps_madds1", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{18, "ps_div", OpType::PS, 17,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV},
{20, "ps_sub", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{21, "ps_add", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{23, "ps_sel", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_IN_FLOAT_BC_BITEXACT | FL_RC_BIT_F | FL_USE_FPU |
FL_PROGRAMEXCEPTION},
{24, "ps_res", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION |
FL_FLOAT_EXCEPTION | FL_FLOAT_DIV},
{25, "ps_mul", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{26, "ps_rsqrte", OpType::PS, 2,
FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION |
FL_FLOAT_EXCEPTION | FL_FLOAT_DIV},
{28, "ps_msub", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{29, "ps_madd", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{30, "ps_nmsub", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{31, "ps_nmadd", OpType::PS, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
}};
constexpr std::array<GekkoOPTemplate, 4> s_table4_3{{
{6, "psq_lx", OpType::LoadPS, 1, FL_OUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE},
{7, "psq_stx", OpType::StorePS, 1, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE},
{38, "psq_lux", OpType::LoadPS, 1,
FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_AB | FL_USE_FPU | FL_LOADSTORE},
{39, "psq_stux", OpType::StorePS, 1,
FL_IN_FLOAT_S | FL_OUT_A | FL_IN_AB | FL_USE_FPU | FL_LOADSTORE},
}};
constexpr std::array<GekkoOPTemplate, 13> s_table19{{
{528, "bcctrx", OpType::Branch, 1, FL_ENDBLOCK | FL_READ_CR_BI},
{16, "bclrx", OpType::Branch, 1, FL_ENDBLOCK | FL_READ_CR_BI},
{257, "crand", OpType::CR, 1, FL_EVIL},
{129, "crandc", OpType::CR, 1, FL_EVIL},
{289, "creqv", OpType::CR, 1, FL_EVIL},
{225, "crnand", OpType::CR, 1, FL_EVIL},
{33, "crnor", OpType::CR, 1, FL_EVIL},
{449, "cror", OpType::CR, 1, FL_EVIL},
{417, "crorc", OpType::CR, 1, FL_EVIL},
{193, "crxor", OpType::CR, 1, FL_EVIL},
{150, "isync", OpType::InstructionCache, 1, FL_EVIL},
{0, "mcrf", OpType::System, 1, FL_EVIL | FL_SET_CRn | FL_READ_CRn},
{50, "rfi", OpType::System, 2, FL_ENDBLOCK | FL_CHECKEXCEPTIONS | FL_PROGRAMEXCEPTION},
}};
constexpr std::array<GekkoOPTemplate, 107> s_table31{{
{266, "addx", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_RC_BIT},
{778, "addox", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE},
{10, "addcx", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT},
{522, "addcox", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT | FL_SET_OE},
{138, "addex", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT},
{650, "addeox", OpType::Integer, 1,
FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE},
{234, "addmex", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT},
{746, "addmeox", OpType::Integer, 1,
FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE},
{202, "addzex", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT},
{714, "addzeox", OpType::Integer, 1,
FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE},
{491, "divwx", OpType::Integer, 40, FL_OUT_D | FL_IN_AB | FL_RC_BIT},
{1003, "divwox", OpType::Integer, 40, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE},
{459, "divwux", OpType::Integer, 40, FL_OUT_D | FL_IN_AB | FL_RC_BIT},
{971, "divwuox", OpType::Integer, 40, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE},
{75, "mulhwx", OpType::Integer, 5, FL_OUT_D | FL_IN_AB | FL_RC_BIT},
{11, "mulhwux", OpType::Integer, 5, FL_OUT_D | FL_IN_AB | FL_RC_BIT},
{235, "mullwx", OpType::Integer, 5, FL_OUT_D | FL_IN_AB | FL_RC_BIT},
{747, "mullwox", OpType::Integer, 5, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE},
{104, "negx", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_RC_BIT},
{616, "negox", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_RC_BIT | FL_SET_OE},
{40, "subfx", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_RC_BIT},
{552, "subfox", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE},
{8, "subfcx", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT},
{520, "subfcox", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT | FL_SET_OE},
{136, "subfex", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT},
{648, "subfeox", OpType::Integer, 1,
FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE},
{232, "subfmex", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT},
{744, "subfmeox", OpType::Integer, 1,
FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE},
{200, "subfzex", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT},
{712, "subfzeox", OpType::Integer, 1,
FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE},
{28, "andx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT},
{60, "andcx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT},
{444, "orx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT},
{124, "norx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT},
{316, "xorx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT},
{412, "orcx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT},
{476, "nandx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT},
{284, "eqvx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT},
{0, "cmp", OpType::Integer, 1, FL_IN_AB | FL_SET_CRn},
{32, "cmpl", OpType::Integer, 1, FL_IN_AB | FL_SET_CRn},
{26, "cntlzwx", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_RC_BIT},
{922, "extshx", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_RC_BIT},
{954, "extsbx", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_RC_BIT},
{536, "srwx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT},
{792, "srawx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_SET_CA | FL_RC_BIT},
{824, "srawix", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_SET_CA | FL_RC_BIT},
{24, "slwx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT},
{54, "dcbst", OpType::DataCache, 5, FL_IN_A0B | FL_LOADSTORE},
{86, "dcbf", OpType::DataCache, 5, FL_IN_A0B | FL_LOADSTORE},
{246, "dcbtst", OpType::DataCache, 2, 0},
{278, "dcbt", OpType::DataCache, 2, 0},
{470, "dcbi", OpType::DataCache, 5, FL_IN_A0B | FL_LOADSTORE | FL_PROGRAMEXCEPTION},
{758, "dcba", OpType::DataCache, 5, 0},
{1014, "dcbz", OpType::DataCache, 5, FL_IN_A0B | FL_LOADSTORE},
// load word
{23, "lwzx", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE},
{55, "lwzux", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE},
// load halfword
{279, "lhzx", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE},
{311, "lhzux", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE},
// load halfword signextend
{343, "lhax", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE},
{375, "lhaux", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE},
// load byte
{87, "lbzx", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE},
{119, "lbzux", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE},
// load byte reverse
{534, "lwbrx", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE},
{790, "lhbrx", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE},
// Conditional load/store (Wii SMP)
{150, "stwcxd", OpType::Store, 1, FL_EVIL | FL_IN_S | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE},
{20, "lwarx", OpType::Load, 1, FL_EVIL | FL_OUT_D | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE},
// load string (Inst these)
{533, "lswx", OpType::Load, 1, FL_EVIL | FL_IN_A0B | FL_OUT_D | FL_LOADSTORE},
{597, "lswi", OpType::Load, 1, FL_EVIL | FL_IN_A0 | FL_OUT_D | FL_LOADSTORE},
// store word
{151, "stwx", OpType::Store, 1, FL_IN_S | FL_IN_A0B | FL_LOADSTORE},
{183, "stwux", OpType::Store, 1, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE},
// store halfword
{407, "sthx", OpType::Store, 1, FL_IN_S | FL_IN_A0B | FL_LOADSTORE},
{439, "sthux", OpType::Store, 1, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE},
// store byte
{215, "stbx", OpType::Store, 1, FL_IN_S | FL_IN_A0B | FL_LOADSTORE},
{247, "stbux", OpType::Store, 1, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE},
// store bytereverse
{662, "stwbrx", OpType::Store, 1, FL_IN_S | FL_IN_A0B | FL_LOADSTORE},
{918, "sthbrx", OpType::Store, 1, FL_IN_S | FL_IN_A0B | FL_LOADSTORE},
{661, "stswx", OpType::Store, 1, FL_EVIL | FL_IN_A0B | FL_LOADSTORE},
{725, "stswi", OpType::Store, 1, FL_EVIL | FL_IN_A0 | FL_LOADSTORE},
// fp load/store
{535, "lfsx", OpType::LoadFP, 1, FL_OUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE},
{567, "lfsux", OpType::LoadFP, 1,
FL_OUT_FLOAT_D | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE},
{599, "lfdx", OpType::LoadFP, 1, FL_INOUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE},
{631, "lfdux", OpType::LoadFP, 1,
FL_INOUT_FLOAT_D | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE},
{663, "stfsx", OpType::StoreFP, 1, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE},
{695, "stfsux", OpType::StoreFP, 1,
FL_IN_FLOAT_S | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE},
{727, "stfdx", OpType::StoreFP, 1, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE},
{759, "stfdux", OpType::StoreFP, 1,
FL_IN_FLOAT_S | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE},
{983, "stfiwx", OpType::StoreFP, 1, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE},
{19, "mfcr", OpType::System, 1, FL_OUT_D | FL_READ_ALL_CR},
{83, "mfmsr", OpType::System, 1, FL_OUT_D | FL_PROGRAMEXCEPTION},
{144, "mtcrf", OpType::System, 1, FL_IN_S | FL_SET_ALL_CR | FL_READ_ALL_CR},
{146, "mtmsr", OpType::System, 1,
FL_IN_S | FL_ENDBLOCK | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION},
{210, "mtsr", OpType::System, 1, FL_IN_S | FL_PROGRAMEXCEPTION},
{242, "mtsrin", OpType::System, 1, FL_IN_SB | FL_PROGRAMEXCEPTION},
{339, "mfspr", OpType::SPR, 1, FL_OUT_D | FL_PROGRAMEXCEPTION},
{467, "mtspr", OpType::SPR, 2, FL_IN_S | FL_PROGRAMEXCEPTION},
{371, "mftb", OpType::System, 1, FL_OUT_D | FL_TIMER | FL_PROGRAMEXCEPTION},
{512, "mcrxr", OpType::System, 1, FL_SET_CRn | FL_READ_CA | FL_SET_CA},
{595, "mfsr", OpType::System, 3, FL_OUT_D | FL_PROGRAMEXCEPTION},
{659, "mfsrin", OpType::System, 3, FL_OUT_D | FL_IN_B | FL_PROGRAMEXCEPTION},
{4, "tw", OpType::System, 2, FL_IN_AB | FL_ENDBLOCK},
{598, "sync", OpType::System, 3, 0},
{982, "icbi", OpType::System, 4, FL_IN_A0B | FL_ENDBLOCK | FL_LOADSTORE},
// Unused instructions on GC
{310, "eciwx", OpType::System, 1, FL_IN_A0B | FL_OUT_D | FL_LOADSTORE},
{438, "ecowx", OpType::System, 1, FL_IN_A0B | FL_IN_S | FL_LOADSTORE},
{854, "eieio", OpType::System, 1, 0},
{306, "tlbie", OpType::System, 1, FL_IN_B | FL_PROGRAMEXCEPTION},
{566, "tlbsync", OpType::System, 1, FL_PROGRAMEXCEPTION},
}};
constexpr std::array<GekkoOPTemplate, 9> s_table59{{
{18, "fdivsx", OpType::SingleFP, 17,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION |
FL_FLOAT_DIV}, // TODO
{20, "fsubsx", OpType::SingleFP, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION},
{21, "faddsx", OpType::SingleFP, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION},
{24, "fresx", OpType::SingleFP, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION |
FL_FLOAT_DIV},
{25, "fmulsx", OpType::SingleFP, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION},
{28, "fmsubsx", OpType::SingleFP, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION},
{29, "fmaddsx", OpType::SingleFP, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION},
{30, "fnmsubsx", OpType::SingleFP, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION},
{31, "fnmaddsx", OpType::SingleFP, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION},
}};
constexpr std::array<GekkoOPTemplate, 15> s_table63{{
{264, "fabsx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU},
// FIXME: fcmp modifies the FPRF flags, but if the flags are clobbered later,
// we don't actually need to calculate or store them here. So FL_READ_FPRF and FL_SET_FPRF is
// not an ideal representation of fcmp's effect on FPRF flags and might result in slightly
// sub-optimal code.
{32, "fcmpo", OpType::DoubleFP, 1,
FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION},
{0, "fcmpu", OpType::DoubleFP, 1,
FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION},
{14, "fctiwx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_FLOAT_EXCEPTION},
{15, "fctiwzx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_FLOAT_EXCEPTION},
{72, "fmrx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU},
{136, "fnabsx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_IN_FLOAT_B_BITEXACT | FL_USE_FPU},
{40, "fnegx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_IN_FLOAT_B_BITEXACT | FL_USE_FPU},
{12, "frspx", OpType::DoubleFP, 1,
FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION},
{64, "mcrfs", OpType::SystemFP, 1, FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF},
{583, "mffsx", OpType::SystemFP, 1, FL_RC_BIT_F | FL_INOUT_FLOAT_D | FL_USE_FPU | FL_READ_FPRF},
{70, "mtfsb0x", OpType::SystemFP, 3, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF},
{38, "mtfsb1x", OpType::SystemFP, 3,
FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION},
{134, "mtfsfix", OpType::SystemFP, 3,
FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION},
{711, "mtfsfx", OpType::SystemFP, 3,
FL_RC_BIT_F | FL_IN_FLOAT_B | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION},
}};
constexpr std::array<GekkoOPTemplate, 10> s_table63_2{{
{18, "fdivx", OpType::DoubleFP, 31,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION | FL_FLOAT_DIV},
{20, "fsubx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION},
{21, "faddx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION},
{23, "fselx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_IN_FLOAT_BC_BITEXACT | FL_RC_BIT_F | FL_USE_FPU},
{25, "fmulx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION},
{26, "frsqrtex", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION | FL_FLOAT_DIV},
{28, "fmsubx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION},
{29, "fmaddx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION},
{30, "fnmsubx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION},
{31, "fnmaddx", OpType::DoubleFP, 1,
FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF |
FL_FLOAT_EXCEPTION},
}};
constexpr size_t TOTAL_INSTRUCTION_COUNT =
1 + s_primary_table.size() + s_table4_2.size() + s_table4_3.size() + s_table4.size() +
s_table31.size() + s_table19.size() + s_table59.size() + s_table63.size() + s_table63_2.size();
struct Tables
{
std::array<GekkoOPInfo, TOTAL_INSTRUCTION_COUNT> all_instructions{};
u32 unknown_op_info;
std::array<u32, 64> primary_table{};
std::array<u32, 1024> table4{};
std::array<u32, 1024> table19{};
std::array<u32, 1024> table31{};
std::array<u32, 32> table59{};
std::array<u32, 1024> table63{};
};
} // namespace
static std::array<GekkoOPStats, TOTAL_INSTRUCTION_COUNT> s_all_instructions_stats;
constexpr Tables s_tables = []() consteval
{
Tables tables{};
u32 counter = 0;
auto make_info = [&](const GekkoOPTemplate& inst) consteval->u32
{
ASSERT(counter < TOTAL_INSTRUCTION_COUNT);
GekkoOPInfo* info = &tables.all_instructions[counter];
info->opname = inst.opname;
info->flags = inst.flags;
info->type = inst.type;
info->num_cycles = inst.num_cycles;
info->stats = &s_all_instructions_stats[counter];
return counter++;
};
u32 unknown_op_info = make_info(s_unknown_op_info);
tables.unknown_op_info = unknown_op_info;
Common::Fill(tables.primary_table, unknown_op_info);
for (auto& tpl : s_primary_table)
{
ASSERT(tables.primary_table[tpl.opcode] == unknown_op_info);
tables.primary_table[tpl.opcode] = make_info(tpl);
};
Common::Fill(tables.table4, unknown_op_info);
for (const auto& tpl : s_table4_2)
{
u32 info = make_info(tpl);
for (u32 i = 0; i < 32; i++)
{
const u32 fill = i << 5;
const u32 op = fill + tpl.opcode;
ASSERT(tables.table4[op] == unknown_op_info);
tables.table4[op] = info;
}
}
for (const auto& tpl : s_table4_3)
{
u32 info = make_info(tpl);
for (u32 i = 0; i < 16; i++)
{
const u32 fill = i << 6;
const u32 op = fill + tpl.opcode;
ASSERT(tables.table4[op] == unknown_op_info);
tables.table4[op] = info;
}
}
for (const auto& tpl : s_table4)
{
const u32 op = tpl.opcode;
ASSERT(tables.table4[op] == unknown_op_info);
tables.table4[op] = make_info(tpl);
}
Common::Fill(tables.table19, unknown_op_info);
for (auto& tpl : s_table19)
{
ASSERT(tables.table19[tpl.opcode] == unknown_op_info);
tables.table19[tpl.opcode] = make_info(tpl);
};
Common::Fill(tables.table31, unknown_op_info);
for (auto& tpl : s_table31)
{
ASSERT(tables.table31[tpl.opcode] == unknown_op_info);
tables.table31[tpl.opcode] = make_info(tpl);
};
Common::Fill(tables.table59, unknown_op_info);
for (auto& tpl : s_table59)
{
ASSERT(tables.table59[tpl.opcode] == unknown_op_info);
tables.table59[tpl.opcode] = make_info(tpl);
};
Common::Fill(tables.table63, unknown_op_info);
for (auto& tpl : s_table63)
{
ASSERT(tables.table63[tpl.opcode] == unknown_op_info);
tables.table63[tpl.opcode] = make_info(tpl);
};
for (const auto& tpl : s_table63_2)
{
u32 info = make_info(tpl);
for (u32 i = 0; i < 32; i++)
{
const u32 fill = i << 5;
const u32 op = fill + tpl.opcode;
ASSERT(tables.table63[op] == unknown_op_info);
tables.table63[op] = info;
}
}
ASSERT(counter == TOTAL_INSTRUCTION_COUNT);
return tables;
}
();
const GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
{
const GekkoOPInfo* info = &s_tables.all_instructions[s_tables.primary_table[inst.OPCD]];
if (info->type == OpType::Subtable)
{
switch (inst.OPCD)
{
case 4:
return m_infoTable4[inst.SUBOP10];
return &s_tables.all_instructions[s_tables.table4[inst.SUBOP10]];
case 19:
return m_infoTable19[inst.SUBOP10];
return &s_tables.all_instructions[s_tables.table19[inst.SUBOP10]];
case 31:
return m_infoTable31[inst.SUBOP10];
return &s_tables.all_instructions[s_tables.table31[inst.SUBOP10]];
case 59:
return m_infoTable59[inst.SUBOP5];
return &s_tables.all_instructions[s_tables.table59[inst.SUBOP5]];
case 63:
return m_infoTable63[inst.SUBOP10];
return &s_tables.all_instructions[s_tables.table63[inst.SUBOP10]];
default:
ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid subtable op {:08x} @ {:08x}", inst.hex,
PowerPC::ppcState.pc);
return nullptr;
return &s_tables.all_instructions[s_tables.unknown_op_info];
}
}
else
@ -62,56 +642,14 @@ GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
{
ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid op {:08x} @ {:08x}", inst.hex,
PowerPC::ppcState.pc);
return nullptr;
return &s_tables.all_instructions[s_tables.unknown_op_info];
}
return m_infoTable[inst.OPCD];
return info;
}
}
Interpreter::Instruction GetInterpreterOp(UGeckoInstruction inst)
{
const GekkoOPInfo* info = m_infoTable[inst.OPCD];
if (info->type == OpType::Subtable)
{
switch (inst.OPCD)
{
case 4:
return Interpreter::m_op_table4[inst.SUBOP10];
case 19:
return Interpreter::m_op_table19[inst.SUBOP10];
case 31:
return Interpreter::m_op_table31[inst.SUBOP10];
case 59:
return Interpreter::m_op_table59[inst.SUBOP5];
case 63:
return Interpreter::m_op_table63[inst.SUBOP10];
default:
ASSERT_MSG(POWERPC, 0, "GetInterpreterOp - invalid subtable op {:08x} @ {:08x}", inst.hex,
PowerPC::ppcState.pc);
return nullptr;
}
}
else
{
if (info->type == OpType::Invalid)
{
ASSERT_MSG(POWERPC, 0, "GetInterpreterOp - invalid op {:08x} @ {:08x}", inst.hex,
PowerPC::ppcState.pc);
return nullptr;
}
return Interpreter::m_op_table[inst.OPCD];
}
}
bool UsesFPU(UGeckoInstruction inst)
{
GekkoOPInfo* const info = GetOpInfo(inst);
return (info->flags & FL_USE_FPU) != 0;
}
#define OPLOG
#define OP_TO_LOG "mtfsb0x"
// #define OPLOG
// #define OP_TO_LOG "mtfsb0x"
#ifdef OPLOG
namespace
@ -123,33 +661,42 @@ std::vector<u32> rsplocations;
const char* GetInstructionName(UGeckoInstruction inst)
{
const GekkoOPInfo* info = GetOpInfo(inst);
return info ? info->opname : nullptr;
return info->opname;
}
bool IsValidInstruction(UGeckoInstruction inst)
{
const GekkoOPInfo* info = GetOpInfo(inst);
return info != nullptr && info->type != OpType::Unknown;
return info->type != OpType::Invalid && info->type != OpType::Unknown;
}
void CountInstruction(UGeckoInstruction inst)
{
GekkoOPInfo* info = GetOpInfo(inst);
if (info)
const GekkoOPInfo* info = GetOpInfo(inst);
info->stats->run_count++;
}
void CountInstructionCompile(const GekkoOPInfo* info, u32 pc)
{
info->stats->compile_count++;
info->stats->last_use = pc;
#ifdef OPLOG
if (!strcmp(info->opname, OP_TO_LOG))
{
info->runCount++;
rsplocations.push_back(pc);
}
#endif
}
void PrintInstructionRunCounts()
{
typedef std::pair<const char*, u64> OpInfo;
std::vector<OpInfo> temp;
temp.reserve(m_numInstructions);
for (size_t i = 0; i < m_numInstructions; ++i)
std::array<OpInfo, TOTAL_INSTRUCTION_COUNT> temp;
for (size_t i = 0; i < TOTAL_INSTRUCTION_COUNT; i++)
{
GekkoOPInfo* pInst = m_allInstructions[i];
temp.emplace_back(pInst->opname, pInst->runCount);
const GekkoOPInfo& info = s_tables.all_instructions[i];
temp[i] = std::make_pair(info.opname, info.stats->run_count);
}
std::sort(temp.begin(), temp.end(),
[](const OpInfo& a, const OpInfo& b) { return a.second > b.second; });
@ -159,7 +706,7 @@ void PrintInstructionRunCounts()
if (inst.second == 0)
break;
DEBUG_LOG_FMT(POWERPC, "{} : {}", inst.first, inst.second);
INFO_LOG_FMT(POWERPC, "{} : {}", inst.first, inst.second);
}
}
@ -168,24 +715,24 @@ void LogCompiledInstructions()
static unsigned int time = 0;
File::IOFile f(fmt::format("{}inst_log{}.txt", File::GetUserPath(D_LOGS_IDX), time), "w");
for (size_t i = 0; i < m_numInstructions; i++)
for (size_t i = 0; i < TOTAL_INSTRUCTION_COUNT; i++)
{
GekkoOPInfo* pInst = m_allInstructions[i];
if (pInst->compileCount > 0)
const GekkoOPInfo& info = s_tables.all_instructions[i];
if (info.stats->compile_count > 0)
{
f.WriteString(fmt::format("{0}\t{1}\t{2}\t{3:08x}\n", pInst->opname, pInst->compileCount,
pInst->runCount, pInst->lastUse));
f.WriteString(fmt::format("{0}\t{1}\t{2}\t{3:08x}\n", info.opname, info.stats->compile_count,
info.stats->run_count, info.stats->last_use));
}
}
f.Open(fmt::format("{}inst_not{}.txt", File::GetUserPath(D_LOGS_IDX), time), "w");
for (size_t i = 0; i < m_numInstructions; i++)
for (size_t i = 0; i < TOTAL_INSTRUCTION_COUNT; i++)
{
GekkoOPInfo* pInst = m_allInstructions[i];
if (pInst->compileCount == 0)
const GekkoOPInfo& info = s_tables.all_instructions[i];
if (info.stats->compile_count == 0)
{
f.WriteString(
fmt::format("{0}\t{1}\t{2}\n", pInst->opname, pInst->compileCount, pInst->runCount));
f.WriteString(fmt::format("{0}\t{1}\t{2}\n", info.opname, info.stats->compile_count,
info.stats->run_count));
}
}

View file

@ -5,6 +5,7 @@
#include <array>
#include <cstddef>
#include <utility>
#include "Common/CommonTypes.h"
#include "Core/PowerPC/Gekko.h"
@ -98,35 +99,31 @@ enum class OpType
Unknown,
};
struct GekkoOPStats
{
u64 run_count;
u32 compile_count;
u32 last_use;
};
struct GekkoOPInfo
{
const char* opname;
OpType type;
u32 num_cycles;
u64 flags;
int numCycles;
u64 runCount;
int compileCount;
u32 lastUse;
// Mutable
GekkoOPStats* stats;
};
extern std::array<GekkoOPInfo*, 64> m_infoTable;
extern std::array<GekkoOPInfo*, 1024> m_infoTable4;
extern std::array<GekkoOPInfo*, 1024> m_infoTable19;
extern std::array<GekkoOPInfo*, 1024> m_infoTable31;
extern std::array<GekkoOPInfo*, 32> m_infoTable59;
extern std::array<GekkoOPInfo*, 1024> m_infoTable63;
extern std::array<GekkoOPInfo*, 512> m_allInstructions;
extern size_t m_numInstructions;
namespace PPCTables
{
GekkoOPInfo* GetOpInfo(UGeckoInstruction inst);
Interpreter::Instruction GetInterpreterOp(UGeckoInstruction inst);
const GekkoOPInfo* GetOpInfo(UGeckoInstruction inst);
bool IsValidInstruction(UGeckoInstruction inst);
bool UsesFPU(UGeckoInstruction inst);
void CountInstruction(UGeckoInstruction inst);
void CountInstructionCompile(const GekkoOPInfo* info, u32 pc);
void PrintInstructionRunCounts();
void LogCompiledInstructions();
const char* GetInstructionName(UGeckoInstruction inst);