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 {
|
||||
const char *name;
|
||||
int value_types;
|
||||
const void *data;
|
||||
};
|
||||
|
||||
enum BlockFlags {
|
||||
|
|
|
@ -16,22 +16,38 @@ namespace jit {
|
|||
namespace backend {
|
||||
namespace interpreter {
|
||||
const Register int_registers[NUM_INT_REGISTERS] = {
|
||||
{"ia", ir::VALUE_INT_MASK}, {"ib", ir::VALUE_INT_MASK},
|
||||
{"ic", ir::VALUE_INT_MASK}, {"id", ir::VALUE_INT_MASK},
|
||||
{"ie", ir::VALUE_INT_MASK}, {"if", ir::VALUE_INT_MASK},
|
||||
{"ig", ir::VALUE_INT_MASK}, {"ih", ir::VALUE_INT_MASK},
|
||||
{"ii", ir::VALUE_INT_MASK}, {"ij", ir::VALUE_INT_MASK},
|
||||
{"ik", ir::VALUE_INT_MASK}, {"il", ir::VALUE_INT_MASK},
|
||||
{"im", ir::VALUE_INT_MASK}, {"in", ir::VALUE_INT_MASK},
|
||||
{"io", ir::VALUE_INT_MASK}, {"ip", ir::VALUE_INT_MASK},
|
||||
{"fa", ir::VALUE_FLOAT_MASK}, {"fb", ir::VALUE_FLOAT_MASK},
|
||||
{"fc", ir::VALUE_FLOAT_MASK}, {"fd", ir::VALUE_FLOAT_MASK},
|
||||
{"fe", ir::VALUE_FLOAT_MASK}, {"ff", ir::VALUE_FLOAT_MASK},
|
||||
{"fg", ir::VALUE_FLOAT_MASK}, {"fh", ir::VALUE_FLOAT_MASK},
|
||||
{"fi", ir::VALUE_FLOAT_MASK}, {"fj", ir::VALUE_FLOAT_MASK},
|
||||
{"fk", ir::VALUE_FLOAT_MASK}, {"fl", ir::VALUE_FLOAT_MASK},
|
||||
{"fm", ir::VALUE_FLOAT_MASK}, {"fn", ir::VALUE_FLOAT_MASK},
|
||||
{"fo", ir::VALUE_FLOAT_MASK}, {"fp", ir::VALUE_FLOAT_MASK}};
|
||||
{"ia", ir::VALUE_INT_MASK, nullptr},
|
||||
{"ib", ir::VALUE_INT_MASK, nullptr},
|
||||
{"ic", ir::VALUE_INT_MASK, nullptr},
|
||||
{"id", ir::VALUE_INT_MASK, nullptr},
|
||||
{"ie", ir::VALUE_INT_MASK, nullptr},
|
||||
{"if", ir::VALUE_INT_MASK, nullptr},
|
||||
{"ig", ir::VALUE_INT_MASK, nullptr},
|
||||
{"ih", ir::VALUE_INT_MASK, nullptr},
|
||||
{"ii", ir::VALUE_INT_MASK, nullptr},
|
||||
{"ij", ir::VALUE_INT_MASK, nullptr},
|
||||
{"ik", ir::VALUE_INT_MASK, nullptr},
|
||||
{"il", ir::VALUE_INT_MASK, nullptr},
|
||||
{"im", ir::VALUE_INT_MASK, nullptr},
|
||||
{"in", ir::VALUE_INT_MASK, nullptr},
|
||||
{"io", ir::VALUE_INT_MASK, nullptr},
|
||||
{"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);
|
||||
|
||||
|
|
|
@ -755,7 +755,7 @@ INT_CALLBACK(UMUL) {
|
|||
using U1 = typename std::make_unsigned<A1>::type;
|
||||
U0 lhs = static_cast<U0>(LOAD_ARG0());
|
||||
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, I16, I16, I16);
|
||||
|
|
|
@ -37,25 +37,87 @@ namespace dvm {
|
|||
namespace jit {
|
||||
namespace backend {
|
||||
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[] = {
|
||||
{"rbx", ir::VALUE_INT_MASK}, {"rbp", ir::VALUE_INT_MASK},
|
||||
{"r12", ir::VALUE_INT_MASK}, {"r13", ir::VALUE_INT_MASK},
|
||||
{"r14", ir::VALUE_INT_MASK}, {"r15", ir::VALUE_INT_MASK},
|
||||
{"xmm6", ir::VALUE_FLOAT_MASK}, {"xmm7", ir::VALUE_FLOAT_MASK},
|
||||
{"xmm8", ir::VALUE_FLOAT_MASK}, {"xmm9", ir::VALUE_FLOAT_MASK},
|
||||
{"xmm10", ir::VALUE_FLOAT_MASK}, {"xmm11", ir::VALUE_FLOAT_MASK}};
|
||||
{"rbx", ir::VALUE_INT_MASK,
|
||||
reinterpret_cast<const void *>(&Xbyak::util::rbx)},
|
||||
{"rbp", ir::VALUE_INT_MASK,
|
||||
reinterpret_cast<const void *>(&Xbyak::util::rbp)},
|
||||
{"r12", ir::VALUE_INT_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);
|
||||
|
||||
#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
|
||||
// extremely useful when profiling to group JITd blocks of code with an actual
|
||||
// symbol name
|
||||
static const size_t x64_codegen_size = 1024 * 1024 * 8;
|
||||
static uint8_t x64_codegen[x64_codegen_size];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
X64Backend::X64Backend(Memory &memory)
|
||||
: 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;
|
||||
dvm::store(
|
||||
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(
|
||||
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 +
|
||||
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 +
|
||||
STACK_SHADOW_SPACE + 24),
|
||||
ex.thread_state.rip + mov.length);
|
||||
|
||||
if (mov.is_load) {
|
||||
// prep argument registers (memory object, guest_addr) for read function
|
||||
ex.thread_state.r[Xbyak::Operand::INT_ARG0] =
|
||||
reinterpret_cast<uint64_t>(&memory_);
|
||||
ex.thread_state.r[Xbyak::Operand::INT_ARG1] =
|
||||
static_cast<uint64_t>(guest_addr);
|
||||
ex.thread_state.r[x64_arg0_idx] = reinterpret_cast<uint64_t>(&memory_);
|
||||
ex.thread_state.r[x64_arg1_idx] = static_cast<uint64_t>(guest_addr);
|
||||
|
||||
// prep function call address for thunk
|
||||
switch (mov.operand_size) {
|
||||
|
@ -206,12 +266,9 @@ bool X64Backend::HandleException(BlockPointer block, int *block_flags,
|
|||
} else {
|
||||
// prep argument registers (memory object, guest_addr, value) for write
|
||||
// function
|
||||
ex.thread_state.r[Xbyak::Operand::INT_ARG0] =
|
||||
reinterpret_cast<uint64_t>(&memory_);
|
||||
ex.thread_state.r[Xbyak::Operand::INT_ARG1] =
|
||||
static_cast<uint64_t>(guest_addr);
|
||||
ex.thread_state.r[Xbyak::Operand::INT_ARG2] =
|
||||
*(&ex.thread_state.r[mov.reg]);
|
||||
ex.thread_state.r[x64_arg0_idx] = reinterpret_cast<uint64_t>(&memory_);
|
||||
ex.thread_state.r[x64_arg1_idx] = static_cast<uint64_t>(guest_addr);
|
||||
ex.thread_state.r[x64_arg2_idx] = *(&ex.thread_state.r[mov.reg]);
|
||||
|
||||
// prep function call address for thunk
|
||||
switch (mov.operand_size) {
|
||||
|
|
|
@ -11,6 +11,11 @@ namespace x64 {
|
|||
|
||||
extern const Register x64_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 {
|
||||
public:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,16 +11,6 @@ namespace jit {
|
|||
namespace backend {
|
||||
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 {
|
||||
#if PLATFORM_WINDOWS
|
||||
STACK_SHADOW_SPACE = 32,
|
||||
|
@ -48,11 +38,9 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
|||
hw::Memory &memory, void *guest_ctx, int block_flags);
|
||||
|
||||
// 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::Xmm &GetXMMRegister(const ir::Value *v);
|
||||
const Xbyak::Operand &CopyOperand(const ir::Value *v,
|
||||
const Xbyak::Operand &to);
|
||||
const Xbyak::Reg GetRegister(const ir::Value *v);
|
||||
const Xbyak::Xmm GetXMMRegister(const ir::Value *v);
|
||||
void CopyOperand(const ir::Value *v, const Xbyak::Reg &to);
|
||||
|
||||
Xbyak::Label *AllocLabel();
|
||||
|
||||
|
@ -72,6 +60,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
|||
Xbyak::Label *epilog_label_;
|
||||
int modified_marker_;
|
||||
int *modified_;
|
||||
int num_temps_;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue