diff --git a/libxenia.vcxproj b/libxenia.vcxproj index ddb29f09f..53538d182 100644 --- a/libxenia.vcxproj +++ b/libxenia.vcxproj @@ -47,7 +47,6 @@ - @@ -306,7 +305,7 @@ - + diff --git a/libxenia.vcxproj.filters b/libxenia.vcxproj.filters index cd19ffd7e..8a342f6c9 100644 --- a/libxenia.vcxproj.filters +++ b/libxenia.vcxproj.filters @@ -277,9 +277,6 @@ src\xenia\cpu\backend\x64 - - src\xenia\cpu\backend\x64 - src\xenia\cpu\backend\x64 @@ -921,9 +918,6 @@ src\xenia\cpu\backend\x64 - - src\xenia\cpu\backend\x64 - src\xenia\cpu\backend\x64 @@ -1476,6 +1470,9 @@ src\xenia\vfs + + src\xenia\cpu\backend\x64 + diff --git a/src/xenia/cpu/backend/x64/x64_backend.cc b/src/xenia/cpu/backend/x64/x64_backend.cc index f892453b5..50a112c81 100644 --- a/src/xenia/cpu/backend/x64/x64_backend.cc +++ b/src/xenia/cpu/backend/x64/x64_backend.cc @@ -10,9 +10,10 @@ #include "xenia/cpu/backend/x64/x64_backend.h" #include "xenia/cpu/backend/x64/x64_assembler.h" +#include "xenia/cpu/backend/x64/x64_emitter.h" #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/backend/x64/x64_stack_layout.h" #include "xenia/cpu/processor.h" #include "third_party/xbyak/xbyak/xbyak_util.h" @@ -25,6 +26,15 @@ namespace cpu { namespace backend { namespace x64 { +class X64ThunkEmitter : public X64Emitter { + public: + X64ThunkEmitter(X64Backend* backend, XbyakAllocator* allocator); + ~X64ThunkEmitter() override; + HostToGuestThunk EmitHostToGuestThunk(); + GuestToHostThunk EmitGuestToHostThunk(); + ResolveFunctionThunk EmitResolveFunctionThunk(); +}; + X64Backend::X64Backend(Processor* processor) : Backend(processor), code_cache_(nullptr), emitter_data_(0) {} @@ -68,11 +78,11 @@ bool X64Backend::Initialize() { } // Generate thunks used to transition between jitted code and host code. - auto allocator = std::make_unique(); - auto thunk_emitter = std::make_unique(this, allocator.get()); - host_to_guest_thunk_ = thunk_emitter->EmitHostToGuestThunk(); - guest_to_host_thunk_ = thunk_emitter->EmitGuestToHostThunk(); - resolve_function_thunk_ = thunk_emitter->EmitResolveFunctionThunk(); + XbyakAllocator allocator; + X64ThunkEmitter thunk_emitter(this, &allocator); + host_to_guest_thunk_ = thunk_emitter.EmitHostToGuestThunk(); + guest_to_host_thunk_ = thunk_emitter.EmitGuestToHostThunk(); + resolve_function_thunk_ = thunk_emitter.EmitResolveFunctionThunk(); // Set the code cache to use the ResolveFunction thunk for default // indirections. @@ -98,6 +108,178 @@ std::unique_ptr X64Backend::CreateAssembler() { return std::make_unique(this); } +using namespace Xbyak; + +X64ThunkEmitter::X64ThunkEmitter(X64Backend* backend, XbyakAllocator* allocator) + : X64Emitter(backend, allocator) {} + +X64ThunkEmitter::~X64ThunkEmitter() {} + +HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() { + // rcx = target + // rdx = arg0 + // r8 = arg1 + + const size_t stack_size = StackLayout::THUNK_STACK_SIZE; + // rsp + 0 = return address + mov(qword[rsp + 8 * 3], r8); + mov(qword[rsp + 8 * 2], rdx); + mov(qword[rsp + 8 * 1], rcx); + sub(rsp, stack_size); + + mov(qword[rsp + 48], rbx); + mov(qword[rsp + 56], rcx); + mov(qword[rsp + 64], rbp); + mov(qword[rsp + 72], rsi); + mov(qword[rsp + 80], rdi); + mov(qword[rsp + 88], r12); + mov(qword[rsp + 96], r13); + mov(qword[rsp + 104], r14); + mov(qword[rsp + 112], r15); + + /*movaps(ptr[rsp + 128], xmm6); + movaps(ptr[rsp + 144], xmm7); + movaps(ptr[rsp + 160], xmm8); + movaps(ptr[rsp + 176], xmm9); + movaps(ptr[rsp + 192], xmm10); + movaps(ptr[rsp + 208], xmm11); + movaps(ptr[rsp + 224], xmm12); + movaps(ptr[rsp + 240], xmm13); + movaps(ptr[rsp + 256], xmm14); + movaps(ptr[rsp + 272], xmm15);*/ + + mov(rax, rcx); + mov(rcx, rdx); + mov(rdx, r8); + call(rax); + + /*movaps(xmm6, ptr[rsp + 128]); + movaps(xmm7, ptr[rsp + 144]); + movaps(xmm8, ptr[rsp + 160]); + movaps(xmm9, ptr[rsp + 176]); + movaps(xmm10, ptr[rsp + 192]); + movaps(xmm11, ptr[rsp + 208]); + movaps(xmm12, ptr[rsp + 224]); + movaps(xmm13, ptr[rsp + 240]); + movaps(xmm14, ptr[rsp + 256]); + movaps(xmm15, ptr[rsp + 272]);*/ + + mov(rbx, qword[rsp + 48]); + mov(rcx, qword[rsp + 56]); + mov(rbp, qword[rsp + 64]); + mov(rsi, qword[rsp + 72]); + mov(rdi, qword[rsp + 80]); + mov(r12, qword[rsp + 88]); + mov(r13, qword[rsp + 96]); + mov(r14, qword[rsp + 104]); + mov(r15, qword[rsp + 112]); + + add(rsp, stack_size); + mov(rcx, qword[rsp + 8 * 1]); + mov(rdx, qword[rsp + 8 * 2]); + mov(r8, qword[rsp + 8 * 3]); + ret(); + + void* fn = Emplace(0, stack_size); + return (HostToGuestThunk)fn; +} + +GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() { + // rcx = context + // rdx = target function + // r8 = arg0 + // r9 = arg1 + // r10 = arg2 + + const size_t stack_size = StackLayout::THUNK_STACK_SIZE; + // rsp + 0 = return address + mov(qword[rsp + 8 * 2], rdx); + mov(qword[rsp + 8 * 1], rcx); + sub(rsp, stack_size); + + mov(qword[rsp + 48], rbx); + mov(qword[rsp + 56], rcx); + mov(qword[rsp + 64], rbp); + mov(qword[rsp + 72], rsi); + mov(qword[rsp + 80], rdi); + mov(qword[rsp + 88], r12); + mov(qword[rsp + 96], r13); + mov(qword[rsp + 104], r14); + mov(qword[rsp + 112], r15); + + // TODO(benvanik): save things? XMM0-5? + + mov(rax, rdx); + mov(rdx, r8); + mov(r8, r9); + mov(r9, r10); + call(rax); + + mov(rbx, qword[rsp + 48]); + mov(rcx, qword[rsp + 56]); + mov(rbp, qword[rsp + 64]); + mov(rsi, qword[rsp + 72]); + mov(rdi, qword[rsp + 80]); + mov(r12, qword[rsp + 88]); + mov(r13, qword[rsp + 96]); + mov(r14, qword[rsp + 104]); + mov(r15, qword[rsp + 112]); + + add(rsp, stack_size); + mov(rcx, qword[rsp + 8 * 1]); + mov(rdx, qword[rsp + 8 * 2]); + ret(); + + void* fn = Emplace(0, stack_size); + return (HostToGuestThunk)fn; +} + +// X64Emitter handles actually resolving functions. +extern "C" uint64_t ResolveFunction(void* raw_context, uint32_t target_address); + +ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() { + // ebx = target PPC address + // rcx = context + + const size_t stack_size = StackLayout::THUNK_STACK_SIZE; + // rsp + 0 = return address + mov(qword[rsp + 8 * 2], rdx); + mov(qword[rsp + 8 * 1], rcx); + sub(rsp, stack_size); + + mov(qword[rsp + 48], rbx); + mov(qword[rsp + 56], rcx); + mov(qword[rsp + 64], rbp); + mov(qword[rsp + 72], rsi); + mov(qword[rsp + 80], rdi); + mov(qword[rsp + 88], r12); + mov(qword[rsp + 96], r13); + mov(qword[rsp + 104], r14); + mov(qword[rsp + 112], r15); + + mov(rdx, rbx); + mov(rax, uint64_t(&ResolveFunction)); + call(rax); + + mov(rbx, qword[rsp + 48]); + mov(rcx, qword[rsp + 56]); + mov(rbp, qword[rsp + 64]); + mov(rsi, qword[rsp + 72]); + mov(rdi, qword[rsp + 80]); + mov(r12, qword[rsp + 88]); + mov(r13, qword[rsp + 96]); + mov(r14, qword[rsp + 104]); + mov(r15, qword[rsp + 112]); + + add(rsp, stack_size); + mov(rcx, qword[rsp + 8 * 1]); + mov(rdx, qword[rsp + 8 * 2]); + jmp(rax); + + void* fn = Emplace(0, stack_size); + return (ResolveFunctionThunk)fn; +} + } // namespace x64 } // namespace backend } // namespace cpu diff --git a/src/xenia/cpu/backend/x64/x64_backend.h b/src/xenia/cpu/backend/x64/x64_backend.h index 0bbd5c01b..dc390d103 100644 --- a/src/xenia/cpu/backend/x64/x64_backend.h +++ b/src/xenia/cpu/backend/x64/x64_backend.h @@ -38,8 +38,12 @@ class X64Backend : public Backend { X64CodeCache* code_cache() const { return code_cache_; } uint32_t emitter_data() const { return emitter_data_; } + + // Call a generated function, saving all stack parameters. HostToGuestThunk host_to_guest_thunk() const { return host_to_guest_thunk_; } + // Function that guest code can call to transition into host code. GuestToHostThunk guest_to_host_thunk() const { return guest_to_host_thunk_; } + // Function that thunks to the ResolveFunction in X64Emitter. ResolveFunctionThunk resolve_function_thunk() const { return resolve_function_thunk_; } diff --git a/src/xenia/cpu/backend/x64/x64_emitter.cc b/src/xenia/cpu/backend/x64/x64_emitter.cc index a5f0061d5..7a1cbd3de 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.cc +++ b/src/xenia/cpu/backend/x64/x64_emitter.cc @@ -24,10 +24,9 @@ #include "xenia/cpu/backend/x64/x64_code_cache.h" #include "xenia/cpu/backend/x64/x64_function.h" #include "xenia/cpu/backend/x64/x64_sequences.h" -#include "xenia/cpu/backend/x64/x64_thunk_emitter.h" +#include "xenia/cpu/backend/x64/x64_stack_layout.h" #include "xenia/cpu/cpu_flags.h" #include "xenia/cpu/debug_info.h" -#include "xenia/cpu/hir/hir_builder.h" #include "xenia/cpu/processor.h" #include "xenia/cpu/symbol_info.h" #include "xenia/cpu/thread_state.h" diff --git a/src/xenia/cpu/backend/x64/x64_emitter.h b/src/xenia/cpu/backend/x64/x64_emitter.h index c5e895472..c9d1cc4f1 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.h +++ b/src/xenia/cpu/backend/x64/x64_emitter.h @@ -14,6 +14,8 @@ #include "third_party/xbyak/xbyak/xbyak_util.h" #include "xenia/base/arena.h" +#include "xenia/cpu/hir/hir_builder.h" +#include "xenia/cpu/hir/instr.h" #include "xenia/cpu/hir/value.h" #include "xenia/debug/function_trace_data.h" #include "xenia/memory.h" @@ -24,10 +26,6 @@ class DebugInfo; class FunctionInfo; class Processor; class SymbolInfo; -namespace hir { -class HIRBuilder; -class Instr; -} // namespace hir } // namespace cpu } // namespace xe @@ -156,7 +154,6 @@ class X64Emitter : public Xbyak::CodeGenerator { void DebugBreak(); void Trap(uint16_t trap_type = 0); void UnimplementedInstr(const hir::Instr* i); - void UnimplementedExtern(const hir::Instr* i); void Call(const hir::Instr* instr, FunctionInfo* symbol_info); void CallIndirect(const hir::Instr* instr, const Xbyak::Reg64& reg); diff --git a/src/xenia/cpu/backend/x64/x64_thunk_emitter.h b/src/xenia/cpu/backend/x64/x64_stack_layout.h similarity index 82% rename from src/xenia/cpu/backend/x64/x64_thunk_emitter.h rename to src/xenia/cpu/backend/x64/x64_stack_layout.h index 792fca66f..75b6fa470 100644 --- a/src/xenia/cpu/backend/x64/x64_thunk_emitter.h +++ b/src/xenia/cpu/backend/x64/x64_stack_layout.h @@ -2,13 +2,13 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2014 Ben Vanik. All rights reserved. * + * Copyright 2015 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ -#ifndef XENIA_BACKEND_X64_X64_THUNK_EMITTER_H_ -#define XENIA_BACKEND_X64_X64_THUNK_EMITTER_H_ +#ifndef XENIA_BACKEND_X64_X64_STACK_LAYOUT_H_ +#define XENIA_BACKEND_X64_X64_STACK_LAYOUT_H_ #include "xenia/cpu/backend/x64/x64_backend.h" #include "xenia/cpu/backend/x64/x64_emitter.h" @@ -123,24 +123,9 @@ class StackLayout { const static size_t GUEST_CALL_RET_ADDR = 96; }; -class X64ThunkEmitter : public X64Emitter { - public: - X64ThunkEmitter(X64Backend* backend, XbyakAllocator* allocator); - virtual ~X64ThunkEmitter(); - - // Call a generated function, saving all stack parameters. - HostToGuestThunk EmitHostToGuestThunk(); - - // Function that guest code can call to transition into host code. - GuestToHostThunk EmitGuestToHostThunk(); - - // Function that thunks to the ResolveFunction in X64Emitter. - ResolveFunctionThunk EmitResolveFunctionThunk(); -}; - } // namespace x64 } // namespace backend } // namespace cpu } // namespace xe -#endif // XENIA_BACKEND_X64_X64_THUNK_EMITTER_H_ +#endif // XENIA_BACKEND_X64_X64_STACK_LAYOUT_H_ diff --git a/src/xenia/cpu/backend/x64/x64_thunk_emitter.cc b/src/xenia/cpu/backend/x64/x64_thunk_emitter.cc deleted file mode 100644 index 6b2ce971e..000000000 --- a/src/xenia/cpu/backend/x64/x64_thunk_emitter.cc +++ /dev/null @@ -1,194 +0,0 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2014 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#include "xenia/cpu/backend/x64/x64_thunk_emitter.h" - -#include "third_party/xbyak/xbyak/xbyak.h" - -namespace xe { -namespace cpu { -namespace backend { -namespace x64 { - -using namespace Xbyak; - -X64ThunkEmitter::X64ThunkEmitter(X64Backend* backend, XbyakAllocator* allocator) - : X64Emitter(backend, allocator) {} - -X64ThunkEmitter::~X64ThunkEmitter() {} - -HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() { - // rcx = target - // rdx = arg0 - // r8 = arg1 - - const size_t stack_size = StackLayout::THUNK_STACK_SIZE; - // rsp + 0 = return address - mov(qword[rsp + 8 * 3], r8); - mov(qword[rsp + 8 * 2], rdx); - mov(qword[rsp + 8 * 1], rcx); - sub(rsp, stack_size); - - mov(qword[rsp + 48], rbx); - mov(qword[rsp + 56], rcx); - mov(qword[rsp + 64], rbp); - mov(qword[rsp + 72], rsi); - mov(qword[rsp + 80], rdi); - mov(qword[rsp + 88], r12); - mov(qword[rsp + 96], r13); - mov(qword[rsp + 104], r14); - mov(qword[rsp + 112], r15); - - /*movaps(ptr[rsp + 128], xmm6); - movaps(ptr[rsp + 144], xmm7); - movaps(ptr[rsp + 160], xmm8); - movaps(ptr[rsp + 176], xmm9); - movaps(ptr[rsp + 192], xmm10); - movaps(ptr[rsp + 208], xmm11); - movaps(ptr[rsp + 224], xmm12); - movaps(ptr[rsp + 240], xmm13); - movaps(ptr[rsp + 256], xmm14); - movaps(ptr[rsp + 272], xmm15);*/ - - mov(rax, rcx); - mov(rcx, rdx); - mov(rdx, r8); - call(rax); - - /*movaps(xmm6, ptr[rsp + 128]); - movaps(xmm7, ptr[rsp + 144]); - movaps(xmm8, ptr[rsp + 160]); - movaps(xmm9, ptr[rsp + 176]); - movaps(xmm10, ptr[rsp + 192]); - movaps(xmm11, ptr[rsp + 208]); - movaps(xmm12, ptr[rsp + 224]); - movaps(xmm13, ptr[rsp + 240]); - movaps(xmm14, ptr[rsp + 256]); - movaps(xmm15, ptr[rsp + 272]);*/ - - mov(rbx, qword[rsp + 48]); - mov(rcx, qword[rsp + 56]); - mov(rbp, qword[rsp + 64]); - mov(rsi, qword[rsp + 72]); - mov(rdi, qword[rsp + 80]); - mov(r12, qword[rsp + 88]); - mov(r13, qword[rsp + 96]); - mov(r14, qword[rsp + 104]); - mov(r15, qword[rsp + 112]); - - add(rsp, stack_size); - mov(rcx, qword[rsp + 8 * 1]); - mov(rdx, qword[rsp + 8 * 2]); - mov(r8, qword[rsp + 8 * 3]); - ret(); - - void* fn = Emplace(0, stack_size); - return (HostToGuestThunk)fn; -} - -GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() { - // rcx = context - // rdx = target function - // r8 = arg0 - // r9 = arg1 - // r10 = arg2 - - const size_t stack_size = StackLayout::THUNK_STACK_SIZE; - // rsp + 0 = return address - mov(qword[rsp + 8 * 2], rdx); - mov(qword[rsp + 8 * 1], rcx); - sub(rsp, stack_size); - - mov(qword[rsp + 48], rbx); - mov(qword[rsp + 56], rcx); - mov(qword[rsp + 64], rbp); - mov(qword[rsp + 72], rsi); - mov(qword[rsp + 80], rdi); - mov(qword[rsp + 88], r12); - mov(qword[rsp + 96], r13); - mov(qword[rsp + 104], r14); - mov(qword[rsp + 112], r15); - - // TODO(benvanik): save things? XMM0-5? - - mov(rax, rdx); - mov(rdx, r8); - mov(r8, r9); - mov(r9, r10); - call(rax); - - mov(rbx, qword[rsp + 48]); - mov(rcx, qword[rsp + 56]); - mov(rbp, qword[rsp + 64]); - mov(rsi, qword[rsp + 72]); - mov(rdi, qword[rsp + 80]); - mov(r12, qword[rsp + 88]); - mov(r13, qword[rsp + 96]); - mov(r14, qword[rsp + 104]); - mov(r15, qword[rsp + 112]); - - add(rsp, stack_size); - mov(rcx, qword[rsp + 8 * 1]); - mov(rdx, qword[rsp + 8 * 2]); - ret(); - - void* fn = Emplace(0, stack_size); - return (HostToGuestThunk)fn; -} - -// X64Emitter handles actually resolving functions. -extern "C" uint64_t ResolveFunction(void* raw_context, uint32_t target_address); - -ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() { - // ebx = target PPC address - // rcx = context - - const size_t stack_size = StackLayout::THUNK_STACK_SIZE; - // rsp + 0 = return address - mov(qword[rsp + 8 * 2], rdx); - mov(qword[rsp + 8 * 1], rcx); - sub(rsp, stack_size); - - mov(qword[rsp + 48], rbx); - mov(qword[rsp + 56], rcx); - mov(qword[rsp + 64], rbp); - mov(qword[rsp + 72], rsi); - mov(qword[rsp + 80], rdi); - mov(qword[rsp + 88], r12); - mov(qword[rsp + 96], r13); - mov(qword[rsp + 104], r14); - mov(qword[rsp + 112], r15); - - mov(rdx, rbx); - mov(rax, uint64_t(&ResolveFunction)); - call(rax); - - mov(rbx, qword[rsp + 48]); - mov(rcx, qword[rsp + 56]); - mov(rbp, qword[rsp + 64]); - mov(rsi, qword[rsp + 72]); - mov(rdi, qword[rsp + 80]); - mov(r12, qword[rsp + 88]); - mov(r13, qword[rsp + 96]); - mov(r14, qword[rsp + 104]); - mov(r15, qword[rsp + 112]); - - add(rsp, stack_size); - mov(rcx, qword[rsp + 8 * 1]); - mov(rdx, qword[rsp + 8 * 2]); - jmp(rax); - - void* fn = Emplace(0, stack_size); - return (ResolveFunctionThunk)fn; -} - -} // namespace x64 -} // namespace backend -} // namespace cpu -} // namespace xe