Shuffling around thunk emitter.

Progress on #291.
This commit is contained in:
Ben Vanik 2015-06-28 10:43:10 -07:00
parent 5e950cb066
commit 3745746fcc
8 changed files with 203 additions and 234 deletions

View File

@ -47,7 +47,6 @@
<ClCompile Include="src\xenia\cpu\backend\x64\x64_emitter.cc" />
<ClCompile Include="src\xenia\cpu\backend\x64\x64_function.cc" />
<ClCompile Include="src\xenia\cpu\backend\x64\x64_sequences.cc" />
<ClCompile Include="src\xenia\cpu\backend\x64\x64_thunk_emitter.cc" />
<ClCompile Include="src\xenia\cpu\backend\x64\x64_tracers.cc" />
<ClCompile Include="src\xenia\cpu\compiler\compiler.cc" />
<ClCompile Include="src\xenia\cpu\compiler\compiler_pass.cc" />
@ -306,7 +305,7 @@
<ClInclude Include="src\xenia\cpu\backend\x64\x64_emitter.h" />
<ClInclude Include="src\xenia\cpu\backend\x64\x64_function.h" />
<ClInclude Include="src\xenia\cpu\backend\x64\x64_sequences.h" />
<ClInclude Include="src\xenia\cpu\backend\x64\x64_thunk_emitter.h" />
<ClInclude Include="src\xenia\cpu\backend\x64\x64_stack_layout.h" />
<ClInclude Include="src\xenia\cpu\backend\x64\x64_tracers.h" />
<ClInclude Include="src\xenia\cpu\compiler\compiler.h" />
<ClInclude Include="src\xenia\cpu\compiler\compiler_pass.h" />

View File

@ -277,9 +277,6 @@
<ClCompile Include="src\xenia\cpu\backend\x64\x64_sequences.cc">
<Filter>src\xenia\cpu\backend\x64</Filter>
</ClCompile>
<ClCompile Include="src\xenia\cpu\backend\x64\x64_thunk_emitter.cc">
<Filter>src\xenia\cpu\backend\x64</Filter>
</ClCompile>
<ClCompile Include="src\xenia\cpu\backend\x64\x64_tracers.cc">
<Filter>src\xenia\cpu\backend\x64</Filter>
</ClCompile>
@ -921,9 +918,6 @@
<ClInclude Include="src\xenia\cpu\backend\x64\x64_sequences.h">
<Filter>src\xenia\cpu\backend\x64</Filter>
</ClInclude>
<ClInclude Include="src\xenia\cpu\backend\x64\x64_thunk_emitter.h">
<Filter>src\xenia\cpu\backend\x64</Filter>
</ClInclude>
<ClInclude Include="src\xenia\cpu\backend\x64\x64_tracers.h">
<Filter>src\xenia\cpu\backend\x64</Filter>
</ClInclude>
@ -1476,6 +1470,9 @@
<ClInclude Include="src\xenia\vfs\virtual_file_system.h">
<Filter>src\xenia\vfs</Filter>
</ClInclude>
<ClInclude Include="src\xenia\cpu\backend\x64\x64_stack_layout.h">
<Filter>src\xenia\cpu\backend\x64</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="src\xenia\cpu\backend\x64\x64_sequence.inl">

View File

@ -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<XbyakAllocator>();
auto thunk_emitter = std::make_unique<X64ThunkEmitter>(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<Assembler> X64Backend::CreateAssembler() {
return std::make_unique<X64Assembler>(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

View File

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

View File

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

View File

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

View File

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

View File

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