From 0ffd8bbedd1d479e2fef130f6ede70391eca3f5c Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Mon, 15 Jun 2015 18:47:53 -0700 Subject: [PATCH] Place all XMM constants in memory so we can avoid clobbering rax. --- src/xenia/cpu/backend/x64/x64_backend.cc | 14 +++++++-- src/xenia/cpu/backend/x64/x64_backend.h | 3 ++ src/xenia/cpu/backend/x64/x64_code_cache.cc | 34 +++++++++++++++++++++ src/xenia/cpu/backend/x64/x64_code_cache.h | 3 +- src/xenia/cpu/backend/x64/x64_emitter.cc | 16 +++++----- src/xenia/cpu/backend/x64/x64_emitter.h | 3 ++ 6 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/xenia/cpu/backend/x64/x64_backend.cc b/src/xenia/cpu/backend/x64/x64_backend.cc index d6755449c..e02d0a0bb 100644 --- a/src/xenia/cpu/backend/x64/x64_backend.cc +++ b/src/xenia/cpu/backend/x64/x64_backend.cc @@ -13,6 +13,7 @@ #include "xenia/cpu/backend/x64/x64_code_cache.h" #include "xenia/cpu/backend/x64/x64_sequences.h" #include "xenia/cpu/backend/x64/x64_thunk_emitter.h" +#include "xenia/cpu/processor.h" namespace xe { namespace cpu { @@ -20,9 +21,15 @@ namespace backend { namespace x64 { X64Backend::X64Backend(Processor* processor) - : Backend(processor), code_cache_(nullptr) {} + : Backend(processor), code_cache_(nullptr), emitter_data_(0) {} -X64Backend::~X64Backend() { delete code_cache_; } +X64Backend::~X64Backend() { + if (emitter_data_) { + processor()->memory()->SystemHeapFree(emitter_data_); + emitter_data_ = 0; + } + delete code_cache_; +} bool X64Backend::Initialize() { if (!Backend::Initialize()) { @@ -61,6 +68,9 @@ bool X64Backend::Initialize() { // Allocate some special indirections. code_cache_->CommitExecutableRange(0x9FFF0000, 0x9FFFFFFF); + // Allocate emitter constant data. + emitter_data_ = X64Emitter::PlaceData(processor()->memory()); + return true; } diff --git a/src/xenia/cpu/backend/x64/x64_backend.h b/src/xenia/cpu/backend/x64/x64_backend.h index db58260fb..6c85d834e 100644 --- a/src/xenia/cpu/backend/x64/x64_backend.h +++ b/src/xenia/cpu/backend/x64/x64_backend.h @@ -33,6 +33,7 @@ class X64Backend : public Backend { ~X64Backend() override; X64CodeCache* code_cache() const { return code_cache_; } + uint32_t emitter_data() const { return emitter_data_; } HostToGuestThunk host_to_guest_thunk() const { return host_to_guest_thunk_; } GuestToHostThunk guest_to_host_thunk() const { return guest_to_host_thunk_; } ResolveFunctionThunk resolve_function_thunk() const { @@ -48,6 +49,8 @@ class X64Backend : public Backend { private: X64CodeCache* code_cache_; + uint32_t emitter_data_; + HostToGuestThunk host_to_guest_thunk_; GuestToHostThunk guest_to_host_thunk_; ResolveFunctionThunk resolve_function_thunk_; diff --git a/src/xenia/cpu/backend/x64/x64_code_cache.cc b/src/xenia/cpu/backend/x64/x64_code_cache.cc index 6ae976a72..6b02e65e4 100644 --- a/src/xenia/cpu/backend/x64/x64_code_cache.cc +++ b/src/xenia/cpu/backend/x64/x64_code_cache.cc @@ -300,6 +300,40 @@ void X64CodeCache::InitializeUnwindEntry(uint8_t* unwind_entry_address, fn_entry.UnwindData = (DWORD)(unwind_entry_address - generated_code_base_); } +uint32_t X64CodeCache::PlaceData(const void* data, size_t length) { + // Hold a lock while we bump the pointers up. + size_t high_mark; + uint8_t* data_address = nullptr; + size_t unwind_table_slot = 0; + { + std::lock_guard allocation_lock(allocation_mutex_); + + // Reserve code. + // Always move the code to land on 16b alignment. + data_address = generated_code_base_ + generated_code_offset_; + generated_code_offset_ += xe::round_up(length, 16); + + high_mark = generated_code_offset_; + } + + // If we are going above the high water mark of committed memory, commit some + // more. It's ok if multiple threads do this, as redundant commits aren't + // harmful. + size_t old_commit_mark = generated_code_commit_mark_; + if (high_mark > old_commit_mark) { + size_t new_commit_mark = old_commit_mark + 16 * 1024 * 1024; + VirtualAlloc(generated_code_base_, new_commit_mark, MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + generated_code_commit_mark_.compare_exchange_strong(old_commit_mark, + new_commit_mark); + } + + // Copy code. + std::memcpy(data_address, data, length); + + return uint32_t(uintptr_t(data_address)); +} + } // namespace x64 } // namespace backend } // namespace cpu diff --git a/src/xenia/cpu/backend/x64/x64_code_cache.h b/src/xenia/cpu/backend/x64/x64_code_cache.h index 466a3b536..2ee785c5d 100644 --- a/src/xenia/cpu/backend/x64/x64_code_cache.h +++ b/src/xenia/cpu/backend/x64/x64_code_cache.h @@ -36,7 +36,6 @@ class X64CodeCache { // TODO(benvanik): padding/guards/etc void set_indirection_default(uint32_t default_value); - void AddIndirection(uint32_t guest_address, uint32_t host_address); void CommitExecutableRange(uint32_t guest_low, uint32_t guest_high); @@ -44,6 +43,8 @@ class X64CodeCache { void* PlaceCode(uint32_t guest_address, void* machine_code, size_t code_size, size_t stack_size); + uint32_t PlaceData(const void* data, size_t length); + private: const static uint64_t kIndirectionTableBase = 0x80000000; const static uint64_t kIndirectionTableSize = 0x1FFFFFFF; diff --git a/src/xenia/cpu/backend/x64/x64_emitter.cc b/src/xenia/cpu/backend/x64/x64_emitter.cc index 99ca9a82d..bdb303d6a 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.cc +++ b/src/xenia/cpu/backend/x64/x64_emitter.cc @@ -583,7 +583,7 @@ void X64Emitter::MovMem64(const RegExp& addr, uint64_t v) { } } -Address X64Emitter::GetXmmConstPtr(XmmConst id) { +uint32_t X64Emitter::PlaceData(Memory* memory) { static const vec128_t xmm_consts[] = { /* XMMZero */ vec128f(0.0f), /* XMMOne */ vec128f(1.0f), @@ -659,12 +659,14 @@ Address X64Emitter::GetXmmConstPtr(XmmConst id) { /* XMMShortMinPS */ vec128f(SHRT_MIN), /* XMMShortMaxPS */ vec128f(SHRT_MAX), }; - // TODO(benvanik): cache base pointer somewhere? stack? It'd be nice to - // prevent this move. - // TODO(benvanik): move to predictable location in PPCContext? could then - // just do rcx relative addression with no rax overwriting. - mov(rax, (uint64_t)&xmm_consts[id]); - return ptr[rax]; + uint32_t ptr = memory->SystemHeapAlloc(sizeof(xmm_consts)); + std::memcpy(memory->TranslateVirtual(ptr), xmm_consts, sizeof(xmm_consts)); + return ptr; +} + +Address X64Emitter::GetXmmConstPtr(XmmConst id) { + // Load through fixed constant table setup by PlaceData. + return ptr[rdx + backend_->emitter_data() + sizeof(vec128_t) * id]; } void X64Emitter::LoadConstantXmm(Xbyak::Xmm dest, const vec128_t& v) { diff --git a/src/xenia/cpu/backend/x64/x64_emitter.h b/src/xenia/cpu/backend/x64/x64_emitter.h index b1b12ac04..9038e6ea1 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.h +++ b/src/xenia/cpu/backend/x64/x64_emitter.h @@ -16,6 +16,7 @@ #include "xenia/base/arena.h" #include "xenia/cpu/hir/value.h" #include "xenia/debug/function_trace_data.h" +#include "xenia/memory.h" namespace xe { namespace cpu { @@ -117,6 +118,8 @@ class X64Emitter : public Xbyak::CodeGenerator { uint32_t debug_info_flags, DebugInfo* debug_info, void*& out_code_address, size_t& out_code_size); + static uint32_t PlaceData(Memory* memory); + public: // Reserved: rsp // Scratch: rax/rcx/rdx