diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index c9704450ab..13d55216cc 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -244,6 +244,7 @@ if(_M_X86) PowerPC/Jit64/JitRegCache.cpp PowerPC/Jit64/Jit_SystemRegisters.cpp PowerPC/Jit64Common/BlockCache.cpp + PowerPC/Jit64Common/ConstantPool.cpp PowerPC/Jit64Common/EmuCodeBlock.cpp PowerPC/Jit64Common/FarCodeCache.cpp PowerPC/Jit64Common/Jit64AsmCommon.cpp diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 86edd95d87..049aba4703 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -243,6 +243,7 @@ + @@ -484,6 +485,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 18bce72497..e108623f61 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -867,6 +867,9 @@ IOS\USB\Bluetooth + + PowerPC\Jit64Common + @@ -1487,6 +1490,9 @@ IOS + + PowerPC\Jit64Common + diff --git a/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.cpp b/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.cpp new file mode 100644 index 0000000000..20c3f46802 --- /dev/null +++ b/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.cpp @@ -0,0 +1,67 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include + +#include "Common/Assert.h" +#include "Common/x64Emitter.h" +#include "Core/PowerPC/Jit64Common/ConstantPool.h" + +ConstantPool::ConstantPool(Gen::X64CodeBlock* parent) : m_parent(parent) +{ +} + +ConstantPool::~ConstantPool() = default; + +void ConstantPool::AllocCodeSpace() +{ + _assert_(!m_current_ptr); + Init(); +} + +void ConstantPool::ClearCodeSpace() +{ + Init(); +} + +Gen::OpArg ConstantPool::GetConstantOpArg(const void* value, size_t element_size, + size_t num_elements, size_t index) +{ + const size_t value_size = element_size * num_elements; + auto iter = m_const_info.find(value); + + if (iter == m_const_info.end()) + { + void* ptr = std::align(ALIGNMENT, value_size, m_current_ptr, m_remaining_size); + _assert_msg_(DYNA_REC, ptr, "Constant pool has run out of space."); + + m_current_ptr = static_cast(m_current_ptr) + value_size; + m_remaining_size -= value_size; + + std::memcpy(ptr, value, value_size); + iter = m_const_info.emplace(std::make_pair(value, ConstantInfo{ptr, value_size})).first; + } + + const ConstantInfo& info = iter->second; + _assert_msg_(DYNA_REC, info.m_size == value_size, + "Constant has incorrect size in constant pool."); + u8* location = static_cast(info.m_location); + return Gen::M(location + element_size * index); +} + +void ConstantPool::Init() +{ + // If execution happens to run to the start of the constant pool, halt. + m_parent->INT3(); + m_parent->AlignCode16(); + + // Reserve a block of memory CONST_POOL_SIZE in size. + m_current_ptr = m_parent->GetWritableCodePtr(); + m_parent->ReserveCodeSpace(CONST_POOL_SIZE); + + m_remaining_size = CONST_POOL_SIZE; + m_const_info.clear(); +} diff --git a/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.h b/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.h new file mode 100644 index 0000000000..eba5cbec0f --- /dev/null +++ b/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.h @@ -0,0 +1,52 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +namespace Gen +{ +struct OpArg; +class X64CodeBlock; +} + +// Constants are copied into this pool so that they live at a memory location +// that is close to the code that references it. This ensures that the 32-bit +// limitation on RIP addressing is not an issue. +class ConstantPool +{ +public: + static constexpr size_t CONST_POOL_SIZE = 1024 * 32; + static constexpr size_t ALIGNMENT = 16; + + explicit ConstantPool(Gen::X64CodeBlock* parent); + ~ConstantPool(); + + // ConstantPool reserves CONST_POOL_SIZE bytes from parent, and uses + // that space to store its constants. + void AllocCodeSpace(); + void ClearCodeSpace(); + + // Copies the value into the pool if it doesn't exist. Returns a pointer + // to existing values if they were already copied. Pointer equality is + // used to determine if two constants are the same. + Gen::OpArg GetConstantOpArg(const void* value, size_t element_size, size_t num_elements, + size_t index); + +private: + void Init(); + + struct ConstantInfo + { + void* m_location; + size_t m_size; + }; + + Gen::X64CodeBlock* m_parent; + void* m_current_ptr = nullptr; + size_t m_remaining_size = CONST_POOL_SIZE; + std::map m_const_info; +};