From 6bb08de8a04097ec609dd7e893918f6ac096aea8 Mon Sep 17 00:00:00 2001 From: magumagu Date: Sat, 19 Apr 2014 17:39:42 -0700 Subject: [PATCH 1/2] JIT: get rid of useless code in JitCache.cpp. --- .../Core/Core/PowerPC/JitCommon/JitCache.cpp | 18 ------------------ Source/Core/Core/PowerPC/JitCommon/JitCache.h | 4 ---- Source/Core/Core/PowerPC/JitInterface.cpp | 8 ++++++-- 3 files changed, 6 insertions(+), 24 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp index 71143fc955..2c9a4afeb5 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp @@ -116,24 +116,6 @@ using namespace Gen; memset(blockCodePointers, 0, sizeof(u8*)*MAX_NUM_BLOCKS); } - void JitBaseBlockCache::ClearSafe() - { - memset(iCache, JIT_ICACHE_INVALID_BYTE, JIT_ICACHE_SIZE); - memset(iCacheEx, JIT_ICACHE_INVALID_BYTE, JIT_ICACHEEX_SIZE); - memset(iCacheVMEM, JIT_ICACHE_INVALID_BYTE, JIT_ICACHE_SIZE); - } - - /*void JitBaseBlockCache::DestroyBlocksWithFlag(BlockFlag death_flag) - { - for (int i = 0; i < num_blocks; i++) - { - if (blocks[i].flags & death_flag) - { - DestroyBlock(i, false); - } - } - }*/ - void JitBaseBlockCache::Reset() { Shutdown(); diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/PowerPC/JitCommon/JitCache.h index 0837dd371a..ada410a420 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.h @@ -96,7 +96,6 @@ public: void FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr); void Clear(); - void ClearSafe(); void Init(); void Shutdown(); void Reset(); @@ -122,9 +121,6 @@ public: // DOES NOT WORK CORRECTLY WITH INLINING void InvalidateICache(u32 address, const u32 length); void DestroyBlock(int block_num, bool invalidate); - - // Not currently used - //void DestroyBlocksWithFlag(BlockFlag death_flag); }; // x86 BlockCache diff --git a/Source/Core/Core/PowerPC/JitInterface.cpp b/Source/Core/Core/PowerPC/JitInterface.cpp index 281f853911..f959564d51 100644 --- a/Source/Core/Core/PowerPC/JitInterface.cpp +++ b/Source/Core/Core/PowerPC/JitInterface.cpp @@ -39,7 +39,7 @@ namespace JitInterface void DoState(PointerWrap &p) { if (jit && p.GetMode() == PointerWrap::MODE_READ) - jit->GetBlockCache()->ClearSafe(); + jit->GetBlockCache()->Clear(); } CPUCoreBase *InitJitCore(int core) { @@ -199,8 +199,12 @@ namespace JitInterface } void ClearSafe() { + // This clear is "safe" in the sense that it's okay to run from + // inside a JIT'ed block: it clears the instruction cache, but not + // the JIT'ed code. + // TODO: There's probably a better way to handle this situation. if (jit) - jit->GetBlockCache()->ClearSafe(); + jit->GetBlockCache()->Clear(); } void InvalidateICache(u32 address, u32 size) From 282e9bd2922c58e23901cd44ad5cc1d540384788 Mon Sep 17 00:00:00 2001 From: magumagu Date: Sat, 24 May 2014 11:18:32 -0700 Subject: [PATCH 2/2] JitCache: use a custom bit-set class. Unfortunately, this appears to be necessary for the sake of performance; the standard library equivalents don't work well enough on Visual Studio 2013. vector::insert() is way too slow in debug builds to be usable, and std::bitset generates inefficient code in release builds. --- .../Core/Core/PowerPC/JitCommon/JitCache.cpp | 9 ++--- Source/Core/Core/PowerPC/JitCommon/JitCache.h | 39 ++++++++++++++++++- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp index 2c9a4afeb5..a3723253b5 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp @@ -109,8 +109,7 @@ using namespace Gen; links_to.clear(); block_map.clear(); - valid_block.clear(); - valid_block.resize(VALID_BLOCK_MASK_SIZE, false); + valid_block.ClearAll(); num_blocks = 0; memset(blockCodePointers, 0, sizeof(u8*)*MAX_NUM_BLOCKS); @@ -165,7 +164,7 @@ using namespace Gen; u32 pAddr = b.originalAddress & 0x1FFFFFFF; for (u32 i = 0; i < (b.originalSize + 7) / 8; ++i) - valid_block[pAddr / 32 + i] = true; + valid_block.Set(pAddr / 32 + i); block_map[std::make_pair(pAddr + 4 * b.originalSize - 1, pAddr)] = block_num; if (block_link) @@ -335,10 +334,10 @@ using namespace Gen; bool destroy_block = true; if (length == 32) { - if (!valid_block[pAddr / 32]) + if (!valid_block.Test(pAddr / 32)) destroy_block = false; else - valid_block[pAddr / 32] = false; + valid_block.Clear(pAddr / 32); } // destroy JIT blocks diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/PowerPC/JitCommon/JitCache.h index ada410a420..5f5b6aaa0a 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "Core/PowerPC/Gekko.h" @@ -64,6 +65,40 @@ struct JitBlock typedef void (*CompiledCode)(); +// This is essentially just an std::bitset, but Visual Studia 2013's +// implementation of std::bitset is slow. +class ValidBlockBitSet final +{ + enum + { + VALID_BLOCK_MASK_SIZE = 0x20000000 / 32, + VALID_BLOCK_ALLOC_ELEMENTS = VALID_BLOCK_MASK_SIZE / 32 + }; + std::unique_ptr m_valid_block; + +public: + ValidBlockBitSet() + { + m_valid_block.reset(new u32[VALID_BLOCK_ALLOC_ELEMENTS]); + ClearAll(); + } + void Set(u32 bit) + { + m_valid_block[bit / 32] |= 1u << (bit % 32); + } + void Clear(u32 bit) + { + m_valid_block[bit / 32] &= ~(1u << (bit % 32)); + } + void ClearAll() + { + memset(m_valid_block.get(), 0, sizeof(u32) * VALID_BLOCK_ALLOC_ELEMENTS); + } + bool Test(u32 bit) + { + return (m_valid_block[bit / 32] & (1u << (bit % 32))) != 0; + } +}; class JitBaseBlockCache { @@ -72,11 +107,11 @@ class JitBaseBlockCache int num_blocks; std::multimap links_to; std::map, u32> block_map; // (end_addr, start_addr) -> number - std::vector valid_block; + ValidBlockBitSet valid_block; + enum { MAX_NUM_BLOCKS = 65536*2, - VALID_BLOCK_MASK_SIZE = 0x20000000 / 32, }; bool RangeIntersect(int s1, int e1, int s2, int e2) const;