From ee200d09eba5061cf85f185b7238ef2652e68514 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 31 May 2019 11:35:28 -0400 Subject: [PATCH] Jit64/Jit64_Tables: Construct tables at compile-time Utilizing constexpr, we can eliminate the need to construct the tables at runtime and just do all the work at compile-time. Making for less moving parts overall. The general structure is more or less the same, however rather than one single initialization function, each table is built off an immediately executed lambda function. This is nice, since it narrows the scope of the table building logic down to the tables that actually need it. --- Source/Core/Core/PowerPC/Jit64/Jit.cpp | 1 - Source/Core/Core/PowerPC/Jit64/Jit.h | 11 +- .../Core/Core/PowerPC/Jit64/Jit64_Tables.cpp | 317 ++++++++++-------- 3 files changed, 179 insertions(+), 150 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index d34eb55680..827c56dea5 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -330,7 +330,6 @@ bool Jit64::BackPatch(u32 emAddress, SContext* ctx) void Jit64::Init() { - InitializeInstructionTables(); EnableBlockLink(); jo.fastmem_arena = SConfig::GetInstance().bFastmem && Memory::InitFastmemArena(); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.h b/Source/Core/Core/PowerPC/Jit64/Jit.h index d2baa32c8a..33263547da 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/PowerPC/Jit64/Jit.h @@ -131,11 +131,11 @@ public: void DoNothing(UGeckoInstruction _inst); void HLEFunction(UGeckoInstruction _inst); - void DynaRunTable4(UGeckoInstruction _inst); - void DynaRunTable19(UGeckoInstruction _inst); - void DynaRunTable31(UGeckoInstruction _inst); - void DynaRunTable59(UGeckoInstruction _inst); - void DynaRunTable63(UGeckoInstruction _inst); + void DynaRunTable4(UGeckoInstruction inst); + void DynaRunTable19(UGeckoInstruction inst); + void DynaRunTable31(UGeckoInstruction inst); + void DynaRunTable59(UGeckoInstruction inst); + void DynaRunTable63(UGeckoInstruction inst); void addx(UGeckoInstruction inst); void arithcx(UGeckoInstruction inst); @@ -236,7 +236,6 @@ public: void eieio(UGeckoInstruction inst); private: - static void InitializeInstructionTables(); void CompileInstruction(PPCAnalyst::CodeOp& op); bool HandleFunctionHooking(u32 address); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp b/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp index 9dc1380dba..f394d4ab14 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp @@ -2,46 +2,20 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include + #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/Jit64/Jit.h" -static Jit64::Instruction dynaOpTable[64]; -static Jit64::Instruction dynaOpTable4[1024]; -static Jit64::Instruction dynaOpTable19[1024]; -static Jit64::Instruction dynaOpTable31[1024]; -static Jit64::Instruction dynaOpTable59[32]; -static Jit64::Instruction dynaOpTable63[1024]; -void Jit64::DynaRunTable4(UGeckoInstruction _inst) -{ - (this->*dynaOpTable4[_inst.SUBOP10])(_inst); -} -void Jit64::DynaRunTable19(UGeckoInstruction _inst) -{ - (this->*dynaOpTable19[_inst.SUBOP10])(_inst); -} -void Jit64::DynaRunTable31(UGeckoInstruction _inst) -{ - (this->*dynaOpTable31[_inst.SUBOP10])(_inst); -} -void Jit64::DynaRunTable59(UGeckoInstruction _inst) -{ - (this->*dynaOpTable59[_inst.SUBOP5])(_inst); -} -void Jit64::DynaRunTable63(UGeckoInstruction _inst) -{ - (this->*dynaOpTable63[_inst.SUBOP10])(_inst); -} - namespace { struct GekkoOPTemplate { - int opcode; - Jit64::Instruction Inst; + u32 opcode; + Jit64::Instruction fn; }; -} // namespace -const GekkoOPTemplate primarytable[] = { +constexpr std::array s_primary_table{{ {4, &Jit64::DynaRunTable4}, // RunTable4 {19, &Jit64::DynaRunTable19}, // RunTable19 {31, &Jit64::DynaRunTable31}, // RunTable31 @@ -109,9 +83,9 @@ const GekkoOPTemplate primarytable[] = { {61, &Jit64::psq_stXX}, // psq_stu // missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58 -}; +}}; -const GekkoOPTemplate table4[] = { +constexpr std::array s_table4{{ // SUBOP10 {0, &Jit64::ps_cmpXX}, // ps_cmpu0 {32, &Jit64::ps_cmpXX}, // ps_cmpo0 @@ -127,9 +101,9 @@ const GekkoOPTemplate table4[] = { {624, &Jit64::ps_mergeXX}, // ps_merge11 {1014, &Jit64::FallBackToInterpreter}, // dcbz_l -}; +}}; -const GekkoOPTemplate table4_2[] = { +constexpr std::array s_table4_2{{ {10, &Jit64::ps_sum}, // ps_sum0 {11, &Jit64::ps_sum}, // ps_sum1 {12, &Jit64::ps_muls}, // ps_muls0 @@ -147,16 +121,16 @@ const GekkoOPTemplate table4_2[] = { {29, &Jit64::fmaddXX}, // ps_madd {30, &Jit64::fmaddXX}, // ps_nmsub {31, &Jit64::fmaddXX}, // ps_nmadd -}; +}}; -const GekkoOPTemplate table4_3[] = { +constexpr std::array 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 -}; +}}; -const GekkoOPTemplate table19[] = { +constexpr std::array s_table19{{ {528, &Jit64::bcctrx}, // bcctrx {16, &Jit64::bclrx}, // bclrx {257, &Jit64::crXXX}, // crand @@ -172,9 +146,9 @@ const GekkoOPTemplate table19[] = { {0, &Jit64::mcrf}, // mcrf {50, &Jit64::rfi}, // rfi -}; +}}; -const GekkoOPTemplate table31[] = { +constexpr std::array s_table31{{ {266, &Jit64::addx}, // addx {778, &Jit64::addx}, // addox {10, &Jit64::arithcx}, // addcx @@ -314,9 +288,9 @@ const GekkoOPTemplate table31[] = { {854, &Jit64::eieio}, // eieio {306, &Jit64::FallBackToInterpreter}, // tlbie {566, &Jit64::DoNothing}, // tlbsync -}; +}}; -const GekkoOPTemplate table59[] = { +constexpr std::array s_table59{{ {18, &Jit64::fp_arith}, // fdivsx {20, &Jit64::fp_arith}, // fsubsx {21, &Jit64::fp_arith}, // faddsx @@ -326,9 +300,9 @@ const GekkoOPTemplate table59[] = { {29, &Jit64::fmaddXX}, // fmaddsx {30, &Jit64::fmaddXX}, // fnmsubsx {31, &Jit64::fmaddXX}, // fnmaddsx -}; +}}; -const GekkoOPTemplate table63[] = { +constexpr std::array s_table63{{ {264, &Jit64::fsign}, // fabsx {32, &Jit64::fcmpX}, // fcmpo {0, &Jit64::fcmpX}, // fcmpu @@ -345,9 +319,9 @@ const GekkoOPTemplate table63[] = { {38, &Jit64::mtfsb1x}, // mtfsb1x {134, &Jit64::mtfsfix}, // mtfsfix {711, &Jit64::mtfsfx}, // mtfsfx -}; +}}; -const GekkoOPTemplate table63_2[] = { +constexpr std::array s_table63_2{{ {18, &Jit64::fp_arith}, // fdivx {20, &Jit64::fp_arith}, // fsubx {21, &Jit64::fp_arith}, // faddx @@ -358,11 +332,162 @@ const GekkoOPTemplate table63_2[] = { {29, &Jit64::fmaddXX}, // fmaddx {30, &Jit64::fmaddXX}, // fnmsubx {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 's std::fill. Thus, this function exists +// to bridge the gap. +template +constexpr void FillWithFallbacks(std::array& table) +{ + for (auto& entry : table) + { + entry = &Jit64::FallBackToInterpreter; + } +} + +constexpr std::array s_dyna_op_table = [] { + std::array table{}; + FillWithFallbacks(table); + + for (auto& tpl : s_primary_table) + { + table[tpl.opcode] = tpl.fn; + } + + return table; +}(); + +constexpr std::array s_dyna_op_table4 = [] { + std::array table{}; + FillWithFallbacks(table); + + 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; + 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; + table[op] = tpl.fn; + } + } + + for (const auto& tpl : s_table4) + { + const u32 op = tpl.opcode; + table[op] = tpl.fn; + } + + return table; +}(); + +constexpr std::array s_dyna_op_table19 = [] { + std::array table{}; + FillWithFallbacks(table); + + for (const auto& tpl : s_table19) + { + const u32 op = tpl.opcode; + table[op] = tpl.fn; + } + + return table; +}(); + +constexpr std::array s_dyna_op_table31 = [] { + std::array table{}; + FillWithFallbacks(table); + + for (const auto& tpl : s_table31) + { + const u32 op = tpl.opcode; + table[op] = tpl.fn; + } + + return table; +}(); + +constexpr std::array s_dyna_op_table59 = [] { + std::array table{}; + FillWithFallbacks(table); + + for (const auto& tpl : s_table59) + { + const u32 op = tpl.opcode; + table[op] = tpl.fn; + } + + return table; +}(); + +constexpr std::array s_dyna_op_table63 = [] { + std::array table{}; + FillWithFallbacks(table); + + for (const auto& tpl : s_table63) + { + const u32 op = tpl.opcode; + table[op] = 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; + table[op] = tpl.fn; + } + } + + return table; +}(); + +} // Anonymous namespace + +void Jit64::DynaRunTable4(UGeckoInstruction inst) +{ + (this->*s_dyna_op_table4[inst.SUBOP10])(inst); +} + +void Jit64::DynaRunTable19(UGeckoInstruction inst) +{ + (this->*s_dyna_op_table19[inst.SUBOP10])(inst); +} + +void Jit64::DynaRunTable31(UGeckoInstruction inst) +{ + (this->*s_dyna_op_table31[inst.SUBOP10])(inst); +} + +void Jit64::DynaRunTable59(UGeckoInstruction inst) +{ + (this->*s_dyna_op_table59[inst.SUBOP5])(inst); +} + +void Jit64::DynaRunTable63(UGeckoInstruction inst) +{ + (this->*s_dyna_op_table63[inst.SUBOP10])(inst); +} void Jit64::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) @@ -377,97 +502,3 @@ void Jit64::CompileInstruction(PPCAnalyst::CodeOp& op) info->lastUse = js.compilerPC; } } - -void Jit64::InitializeInstructionTables() -{ - // once initialized, tables are read-only - static bool initialized = false; - if (initialized) - return; - - // clear - for (auto& tpl : dynaOpTable) - { - tpl = &Jit64::FallBackToInterpreter; - } - - for (auto& tpl : dynaOpTable59) - { - tpl = &Jit64::FallBackToInterpreter; - } - - for (int i = 0; i < 1024; i++) - { - dynaOpTable4[i] = &Jit64::FallBackToInterpreter; - dynaOpTable19[i] = &Jit64::FallBackToInterpreter; - dynaOpTable31[i] = &Jit64::FallBackToInterpreter; - dynaOpTable63[i] = &Jit64::FallBackToInterpreter; - } - - for (auto& tpl : primarytable) - { - dynaOpTable[tpl.opcode] = tpl.Inst; - } - - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (const auto& tpl : table4_2) - { - int op = fill + tpl.opcode; - dynaOpTable4[op] = tpl.Inst; - } - } - - for (int i = 0; i < 16; i++) - { - int fill = i << 6; - for (const auto& tpl : table4_3) - { - int op = fill + tpl.opcode; - dynaOpTable4[op] = tpl.Inst; - } - } - - for (const auto& tpl : table4) - { - int op = tpl.opcode; - dynaOpTable4[op] = tpl.Inst; - } - - for (const auto& tpl : table31) - { - int op = tpl.opcode; - dynaOpTable31[op] = tpl.Inst; - } - - for (const auto& tpl : table19) - { - int op = tpl.opcode; - dynaOpTable19[op] = tpl.Inst; - } - - for (const auto& tpl : table59) - { - int op = tpl.opcode; - dynaOpTable59[op] = tpl.Inst; - } - - for (const auto& tpl : table63) - { - int op = tpl.opcode; - dynaOpTable63[op] = tpl.Inst; - } - - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (const auto& tpl : table63_2) - { - int op = fill + tpl.opcode; - dynaOpTable63[op] = tpl.Inst; - } - } - - initialized = true; -}