Place all XMM constants in memory so we can avoid clobbering rax.

This commit is contained in:
Ben Vanik 2015-06-15 18:47:53 -07:00
parent 329a03e7c4
commit 0ffd8bbedd
6 changed files with 63 additions and 10 deletions

View File

@ -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;
}

View File

@ -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_;

View File

@ -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<xe::mutex> 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

View File

@ -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;

View File

@ -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) {

View File

@ -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