mirror of https://github.com/inolen/redream.git
consolidate x64 register layout information
added support for a second temporary, fixes several emitting issues
This commit is contained in:
parent
d16aac170a
commit
4b42923567
|
@ -18,6 +18,7 @@ namespace backend {
|
||||||
struct Register {
|
struct Register {
|
||||||
const char *name;
|
const char *name;
|
||||||
int value_types;
|
int value_types;
|
||||||
|
const void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BlockFlags {
|
enum BlockFlags {
|
||||||
|
|
|
@ -16,22 +16,38 @@ namespace jit {
|
||||||
namespace backend {
|
namespace backend {
|
||||||
namespace interpreter {
|
namespace interpreter {
|
||||||
const Register int_registers[NUM_INT_REGISTERS] = {
|
const Register int_registers[NUM_INT_REGISTERS] = {
|
||||||
{"ia", ir::VALUE_INT_MASK}, {"ib", ir::VALUE_INT_MASK},
|
{"ia", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"ic", ir::VALUE_INT_MASK}, {"id", ir::VALUE_INT_MASK},
|
{"ib", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"ie", ir::VALUE_INT_MASK}, {"if", ir::VALUE_INT_MASK},
|
{"ic", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"ig", ir::VALUE_INT_MASK}, {"ih", ir::VALUE_INT_MASK},
|
{"id", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"ii", ir::VALUE_INT_MASK}, {"ij", ir::VALUE_INT_MASK},
|
{"ie", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"ik", ir::VALUE_INT_MASK}, {"il", ir::VALUE_INT_MASK},
|
{"if", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"im", ir::VALUE_INT_MASK}, {"in", ir::VALUE_INT_MASK},
|
{"ig", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"io", ir::VALUE_INT_MASK}, {"ip", ir::VALUE_INT_MASK},
|
{"ih", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"fa", ir::VALUE_FLOAT_MASK}, {"fb", ir::VALUE_FLOAT_MASK},
|
{"ii", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"fc", ir::VALUE_FLOAT_MASK}, {"fd", ir::VALUE_FLOAT_MASK},
|
{"ij", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"fe", ir::VALUE_FLOAT_MASK}, {"ff", ir::VALUE_FLOAT_MASK},
|
{"ik", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"fg", ir::VALUE_FLOAT_MASK}, {"fh", ir::VALUE_FLOAT_MASK},
|
{"il", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"fi", ir::VALUE_FLOAT_MASK}, {"fj", ir::VALUE_FLOAT_MASK},
|
{"im", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"fk", ir::VALUE_FLOAT_MASK}, {"fl", ir::VALUE_FLOAT_MASK},
|
{"in", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"fm", ir::VALUE_FLOAT_MASK}, {"fn", ir::VALUE_FLOAT_MASK},
|
{"io", ir::VALUE_INT_MASK, nullptr},
|
||||||
{"fo", ir::VALUE_FLOAT_MASK}, {"fp", ir::VALUE_FLOAT_MASK}};
|
{"ip", ir::VALUE_INT_MASK, nullptr},
|
||||||
|
{"fa", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fb", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fc", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fd", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fe", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"ff", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fg", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fh", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fi", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fj", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fk", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fl", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fm", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fn", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fo", ir::VALUE_FLOAT_MASK, nullptr},
|
||||||
|
{"fp", ir::VALUE_FLOAT_MASK, nullptr}};
|
||||||
|
|
||||||
const int int_num_registers = sizeof(int_registers) / sizeof(Register);
|
const int int_num_registers = sizeof(int_registers) / sizeof(Register);
|
||||||
|
|
||||||
|
|
|
@ -755,7 +755,7 @@ INT_CALLBACK(UMUL) {
|
||||||
using U1 = typename std::make_unsigned<A1>::type;
|
using U1 = typename std::make_unsigned<A1>::type;
|
||||||
U0 lhs = static_cast<U0>(LOAD_ARG0());
|
U0 lhs = static_cast<U0>(LOAD_ARG0());
|
||||||
U1 rhs = static_cast<U1>(LOAD_ARG1());
|
U1 rhs = static_cast<U1>(LOAD_ARG1());
|
||||||
STORE_RESULT((A0)(lhs * rhs));
|
STORE_RESULT(static_cast<A0>(lhs * rhs));
|
||||||
}
|
}
|
||||||
REGISTER_INT_CALLBACK(UMUL, UMUL, I8, I8, I8);
|
REGISTER_INT_CALLBACK(UMUL, UMUL, I8, I8, I8);
|
||||||
REGISTER_INT_CALLBACK(UMUL, UMUL, I16, I16, I16);
|
REGISTER_INT_CALLBACK(UMUL, UMUL, I16, I16, I16);
|
||||||
|
|
|
@ -37,25 +37,87 @@ namespace dvm {
|
||||||
namespace jit {
|
namespace jit {
|
||||||
namespace backend {
|
namespace backend {
|
||||||
namespace x64 {
|
namespace x64 {
|
||||||
|
// x64 register layout
|
||||||
|
|
||||||
|
// %rax %eax %ax %al <-- temporary
|
||||||
|
// %rcx %ecx %cx %cl <-- argument
|
||||||
|
// %rdx %edx %dx %dl <-- argument
|
||||||
|
// %rbx %ebx %bx %bl <-- available, callee saved
|
||||||
|
// %rsp %esp %sp %spl <-- reserved
|
||||||
|
// %rbp %ebp %bp %bpl <-- available, callee saved
|
||||||
|
// %rsi %esi %si %sil <-- argument
|
||||||
|
// %rdi %edi %di %dil <-- argument
|
||||||
|
// %r8 %r8d %r8w %r8b <-- argument
|
||||||
|
// %r9 %r9d %r9w %r9b <-- argument
|
||||||
|
// %r10 %r10d %r10w %r10b <-- available, not callee saved
|
||||||
|
// %r11 %r11d %r11w %r11b <-- available, not callee saved
|
||||||
|
// %r12 %r12d %r12w %r12b <-- available, callee saved
|
||||||
|
// %r13 %r13d %r13w %r13b <-- available, callee saved
|
||||||
|
// %r14 %r14d %r14w %r14b <-- available, callee saved
|
||||||
|
// %r15 %r15d %r15w %r15b <-- available, callee saved
|
||||||
|
|
||||||
|
// msvc calling convention uses rcx, rdx, r8 and r9 for arguments
|
||||||
|
// amd64 calling convention uses rdi, rsi, rdx, rcx, r8 and r9 for arguments
|
||||||
|
// both use the same xmm registers for floating point arguments
|
||||||
|
// our largest function call uses only 3 arguments, leaving rdi, rsi and r9
|
||||||
|
// available on msvc and rcx, r8 and r9 available on amd64
|
||||||
|
|
||||||
|
// rax is used as a scratch register, while rdi/r8, r9 and xmm1 are used for
|
||||||
|
// storing
|
||||||
|
// a constant in case the constant propagation pass didn't eliminate it
|
||||||
|
|
||||||
|
// rsi is left unused on msvc and rcx is left unused on amd64
|
||||||
const Register x64_registers[] = {
|
const Register x64_registers[] = {
|
||||||
{"rbx", ir::VALUE_INT_MASK}, {"rbp", ir::VALUE_INT_MASK},
|
{"rbx", ir::VALUE_INT_MASK,
|
||||||
{"r12", ir::VALUE_INT_MASK}, {"r13", ir::VALUE_INT_MASK},
|
reinterpret_cast<const void *>(&Xbyak::util::rbx)},
|
||||||
{"r14", ir::VALUE_INT_MASK}, {"r15", ir::VALUE_INT_MASK},
|
{"rbp", ir::VALUE_INT_MASK,
|
||||||
{"xmm6", ir::VALUE_FLOAT_MASK}, {"xmm7", ir::VALUE_FLOAT_MASK},
|
reinterpret_cast<const void *>(&Xbyak::util::rbp)},
|
||||||
{"xmm8", ir::VALUE_FLOAT_MASK}, {"xmm9", ir::VALUE_FLOAT_MASK},
|
{"r12", ir::VALUE_INT_MASK,
|
||||||
{"xmm10", ir::VALUE_FLOAT_MASK}, {"xmm11", ir::VALUE_FLOAT_MASK}};
|
reinterpret_cast<const void *>(&Xbyak::util::r12)},
|
||||||
|
{"r13", ir::VALUE_INT_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::r13)},
|
||||||
|
{"r14", ir::VALUE_INT_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::r14)},
|
||||||
|
{"r15", ir::VALUE_INT_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::r15)},
|
||||||
|
{"xmm6", ir::VALUE_FLOAT_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::xmm6)},
|
||||||
|
{"xmm7", ir::VALUE_FLOAT_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::xmm7)},
|
||||||
|
{"xmm8", ir::VALUE_FLOAT_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::xmm8)},
|
||||||
|
{"xmm9", ir::VALUE_FLOAT_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::xmm9)},
|
||||||
|
{"xmm10", ir::VALUE_FLOAT_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::xmm10)},
|
||||||
|
{"xmm11", ir::VALUE_FLOAT_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::xmm11)}};
|
||||||
|
|
||||||
const int x64_num_registers = sizeof(x64_registers) / sizeof(Register);
|
const int x64_num_registers = sizeof(x64_registers) / sizeof(Register);
|
||||||
|
|
||||||
|
#if PLATFORM_WINDOWS
|
||||||
|
const int x64_arg0_idx = Xbyak::Operand::RCX;
|
||||||
|
const int x64_arg1_idx = Xbyak::Operand::RDX;
|
||||||
|
const int x64_arg2_idx = Xbyak::Operand::R8;
|
||||||
|
const int x64_tmp0_idx = Xbyak::Operand::RDI;
|
||||||
|
const int x64_tmp1_idx = Xbyak::Operand::R9;
|
||||||
|
#else
|
||||||
|
const int x64_arg0_idx = Xbyak::Operand::RDI;
|
||||||
|
const int x64_arg1_idx = Xbyak::Operand::RSI;
|
||||||
|
const int x64_arg2_idx = Xbyak::Operand::RDX;
|
||||||
|
const int x64_tmp0_idx = Xbyak::Operand::R8;
|
||||||
|
const int x64_tmp1_idx = Xbyak::Operand::R9;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this will break down if running two instances of the x64 backend, but it's
|
// this will break down if running two instances of the x64 backend, but it's
|
||||||
// extremely useful when profiling to group JITd blocks of code with an actual
|
// extremely useful when profiling to group JITd blocks of code with an actual
|
||||||
// symbol name
|
// symbol name
|
||||||
static const size_t x64_codegen_size = 1024 * 1024 * 8;
|
static const size_t x64_codegen_size = 1024 * 1024 * 8;
|
||||||
static uint8_t x64_codegen[x64_codegen_size];
|
static uint8_t x64_codegen[x64_codegen_size];
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
X64Backend::X64Backend(Memory &memory)
|
X64Backend::X64Backend(Memory &memory)
|
||||||
: Backend(memory), emitter_(x64_codegen, x64_codegen_size) {}
|
: Backend(memory), emitter_(x64_codegen, x64_codegen_size) {}
|
||||||
|
@ -114,23 +176,21 @@ bool X64Backend::HandleException(BlockPointer block, int *block_flags,
|
||||||
ex.thread_state.rsp -= STACK_SHADOW_SPACE + 24 + 8;
|
ex.thread_state.rsp -= STACK_SHADOW_SPACE + 24 + 8;
|
||||||
dvm::store(
|
dvm::store(
|
||||||
reinterpret_cast<uint8_t *>(ex.thread_state.rsp + STACK_SHADOW_SPACE),
|
reinterpret_cast<uint8_t *>(ex.thread_state.rsp + STACK_SHADOW_SPACE),
|
||||||
ex.thread_state.r[Xbyak::Operand::INT_ARG2]);
|
ex.thread_state.r[x64_arg2_idx]);
|
||||||
dvm::store(
|
dvm::store(
|
||||||
reinterpret_cast<uint8_t *>(ex.thread_state.rsp + STACK_SHADOW_SPACE + 8),
|
reinterpret_cast<uint8_t *>(ex.thread_state.rsp + STACK_SHADOW_SPACE + 8),
|
||||||
ex.thread_state.r[Xbyak::Operand::INT_ARG1]);
|
ex.thread_state.r[x64_arg1_idx]);
|
||||||
dvm::store(reinterpret_cast<uint8_t *>(ex.thread_state.rsp +
|
dvm::store(reinterpret_cast<uint8_t *>(ex.thread_state.rsp +
|
||||||
STACK_SHADOW_SPACE + 16),
|
STACK_SHADOW_SPACE + 16),
|
||||||
ex.thread_state.r[Xbyak::Operand::INT_ARG0]);
|
ex.thread_state.r[x64_arg0_idx]);
|
||||||
dvm::store(reinterpret_cast<uint8_t *>(ex.thread_state.rsp +
|
dvm::store(reinterpret_cast<uint8_t *>(ex.thread_state.rsp +
|
||||||
STACK_SHADOW_SPACE + 24),
|
STACK_SHADOW_SPACE + 24),
|
||||||
ex.thread_state.rip + mov.length);
|
ex.thread_state.rip + mov.length);
|
||||||
|
|
||||||
if (mov.is_load) {
|
if (mov.is_load) {
|
||||||
// prep argument registers (memory object, guest_addr) for read function
|
// prep argument registers (memory object, guest_addr) for read function
|
||||||
ex.thread_state.r[Xbyak::Operand::INT_ARG0] =
|
ex.thread_state.r[x64_arg0_idx] = reinterpret_cast<uint64_t>(&memory_);
|
||||||
reinterpret_cast<uint64_t>(&memory_);
|
ex.thread_state.r[x64_arg1_idx] = static_cast<uint64_t>(guest_addr);
|
||||||
ex.thread_state.r[Xbyak::Operand::INT_ARG1] =
|
|
||||||
static_cast<uint64_t>(guest_addr);
|
|
||||||
|
|
||||||
// prep function call address for thunk
|
// prep function call address for thunk
|
||||||
switch (mov.operand_size) {
|
switch (mov.operand_size) {
|
||||||
|
@ -206,12 +266,9 @@ bool X64Backend::HandleException(BlockPointer block, int *block_flags,
|
||||||
} else {
|
} else {
|
||||||
// prep argument registers (memory object, guest_addr, value) for write
|
// prep argument registers (memory object, guest_addr, value) for write
|
||||||
// function
|
// function
|
||||||
ex.thread_state.r[Xbyak::Operand::INT_ARG0] =
|
ex.thread_state.r[x64_arg0_idx] = reinterpret_cast<uint64_t>(&memory_);
|
||||||
reinterpret_cast<uint64_t>(&memory_);
|
ex.thread_state.r[x64_arg1_idx] = static_cast<uint64_t>(guest_addr);
|
||||||
ex.thread_state.r[Xbyak::Operand::INT_ARG1] =
|
ex.thread_state.r[x64_arg2_idx] = *(&ex.thread_state.r[mov.reg]);
|
||||||
static_cast<uint64_t>(guest_addr);
|
|
||||||
ex.thread_state.r[Xbyak::Operand::INT_ARG2] =
|
|
||||||
*(&ex.thread_state.r[mov.reg]);
|
|
||||||
|
|
||||||
// prep function call address for thunk
|
// prep function call address for thunk
|
||||||
switch (mov.operand_size) {
|
switch (mov.operand_size) {
|
||||||
|
|
|
@ -11,6 +11,11 @@ namespace x64 {
|
||||||
|
|
||||||
extern const Register x64_registers[];
|
extern const Register x64_registers[];
|
||||||
extern const int x64_num_registers;
|
extern const int x64_num_registers;
|
||||||
|
extern const int x64_arg0_idx;
|
||||||
|
extern const int x64_arg1_idx;
|
||||||
|
extern const int x64_arg2_idx;
|
||||||
|
extern const int x64_tmp0_idx;
|
||||||
|
extern const int x64_tmp1_idx;
|
||||||
|
|
||||||
class X64Backend : public Backend {
|
class X64Backend : public Backend {
|
||||||
public:
|
public:
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,16 +11,6 @@ namespace jit {
|
||||||
namespace backend {
|
namespace backend {
|
||||||
namespace x64 {
|
namespace x64 {
|
||||||
|
|
||||||
#if PLATFORM_WINDOWS
|
|
||||||
#define INT_ARG0 RCX
|
|
||||||
#define INT_ARG1 RDX
|
|
||||||
#define INT_ARG2 R8
|
|
||||||
#else
|
|
||||||
#define INT_ARG0 RDI
|
|
||||||
#define INT_ARG1 RSI
|
|
||||||
#define INT_ARG2 RDX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS
|
||||||
STACK_SHADOW_SPACE = 32,
|
STACK_SHADOW_SPACE = 32,
|
||||||
|
@ -48,11 +38,9 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||||
hw::Memory &memory, void *guest_ctx, int block_flags);
|
hw::Memory &memory, void *guest_ctx, int block_flags);
|
||||||
|
|
||||||
// helpers for the emitter callbacks
|
// helpers for the emitter callbacks
|
||||||
const Xbyak::Operand &GetOperand(const ir::Value *v, int size = -1);
|
const Xbyak::Reg GetRegister(const ir::Value *v);
|
||||||
const Xbyak::Reg &GetRegister(const ir::Value *v);
|
const Xbyak::Xmm GetXMMRegister(const ir::Value *v);
|
||||||
const Xbyak::Xmm &GetXMMRegister(const ir::Value *v);
|
void CopyOperand(const ir::Value *v, const Xbyak::Reg &to);
|
||||||
const Xbyak::Operand &CopyOperand(const ir::Value *v,
|
|
||||||
const Xbyak::Operand &to);
|
|
||||||
|
|
||||||
Xbyak::Label *AllocLabel();
|
Xbyak::Label *AllocLabel();
|
||||||
|
|
||||||
|
@ -72,6 +60,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||||
Xbyak::Label *epilog_label_;
|
Xbyak::Label *epilog_label_;
|
||||||
int modified_marker_;
|
int modified_marker_;
|
||||||
int *modified_;
|
int *modified_;
|
||||||
|
int num_temps_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue