mirror of
https://github.com/pound-emu/rem.git
synced 2026-06-17 04:16:28 -07:00
added SSA
This commit is contained in:
@@ -3,7 +3,10 @@
|
||||
|
||||
enum compiler_flags
|
||||
{
|
||||
check_undefined_behavior = 1ULL << 0,
|
||||
check_undefined_behavior = 1ULL << 0,
|
||||
optimize_ssa = 1ULL << 1,
|
||||
mathmatical_fold = optimize_ssa | 1ULL << 2,
|
||||
pointer_loading_fold = optimize_ssa | 1ULL << 3,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -438,7 +438,10 @@ void assemble_x86_64_code(void** result_code, uint64_t* result_code_size, ir_ope
|
||||
{
|
||||
uint64_t imm = sources[1].value;
|
||||
|
||||
assert(imm <= INT32_MAX);
|
||||
if (imm >= INT32_MAX)
|
||||
{
|
||||
throw_error();
|
||||
}
|
||||
|
||||
switch (instruction)
|
||||
{
|
||||
@@ -486,6 +489,7 @@ void assemble_x86_64_code(void** result_code, uint64_t* result_code_size, ir_ope
|
||||
}; break;
|
||||
|
||||
case ir_close_and_return:
|
||||
case ir_table_jump:
|
||||
{
|
||||
ir_operand value = working_operation.sources[0];
|
||||
ir_operand context_size = working_operation.sources[1];
|
||||
@@ -502,7 +506,14 @@ void assemble_x86_64_code(void** result_code, uint64_t* result_code_size, ir_ope
|
||||
c.mov(c.rax, create_operand<Xbyak::Reg64>(value));
|
||||
}
|
||||
|
||||
c.ret();
|
||||
if (instruction == ir_close_and_return)
|
||||
{
|
||||
c.ret();
|
||||
}
|
||||
else
|
||||
{
|
||||
c.jmp(c.rax);
|
||||
}
|
||||
|
||||
}; break;
|
||||
|
||||
@@ -740,6 +751,24 @@ void assemble_x86_64_code(void** result_code, uint64_t* result_code_size, ir_ope
|
||||
c.movq(create_operand<Xbyak::Xmm>(d), create_operand<Xbyak::Reg64>(s));
|
||||
}; break;
|
||||
|
||||
case x86_lea:
|
||||
{
|
||||
assert_operand_count(&working_operation, 1, 2);
|
||||
|
||||
ir_operand d = working_operation.destinations[0];
|
||||
ir_operand s0 = working_operation.sources[0];
|
||||
ir_operand s1 = working_operation.sources[1];
|
||||
|
||||
switch (d.meta_data)
|
||||
{
|
||||
case int32: c.lea(create_operand<Xbyak::Reg32>(d), c.ptr[create_operand<Xbyak::Reg32>(s0) + create_operand<Xbyak::Reg32>(s1)]); break;
|
||||
case int64: c.lea(create_operand<Xbyak::Reg64>(d), c.ptr[create_operand<Xbyak::Reg64>(s0) + create_operand<Xbyak::Reg64>(s1)]); break;
|
||||
|
||||
default: throw_error();
|
||||
}
|
||||
|
||||
}; break;
|
||||
|
||||
case x86_addpd: assert_valid_binary_float_operation(&working_operation); c.addpd(create_operand<Xbyak::Xmm>(working_operation.destinations[0]), create_operand<Xbyak::Xmm>(working_operation.sources[1])); break;
|
||||
case x86_addps: assert_valid_binary_float_operation(&working_operation); c.addps(create_operand<Xbyak::Xmm>(working_operation.destinations[0]), create_operand<Xbyak::Xmm>(working_operation.sources[1])); break;
|
||||
case x86_addsd: assert_valid_binary_float_operation(&working_operation); c.addsd(create_operand<Xbyak::Xmm>(working_operation.destinations[0]), create_operand<Xbyak::Xmm>(working_operation.sources[1])); break;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "x86_pre_allocator.h"
|
||||
#include "x86_assembler.h"
|
||||
#include "debugging.h"
|
||||
#include "ir/ssa.h"
|
||||
|
||||
#include "ir/basic_register_allocator.h"
|
||||
#include "ir/undefined_behavior_check.h"
|
||||
@@ -28,6 +29,11 @@ void assemble_x86_64_pipeline(void** result_code, uint64_t* result_code_size, ir
|
||||
|
||||
source_ir = undefined_behavior_checked_code;
|
||||
}
|
||||
|
||||
if (flags & optimize_ssa)
|
||||
{
|
||||
ssa_construct_and_optimize(source_ir, flags);
|
||||
}
|
||||
|
||||
x86_pre_allocator_context::run_pass(&pre_allocation_data, pre_allocated_code, source_ir, working_abi.cpu,working_abi.os);
|
||||
|
||||
|
||||
@@ -169,26 +169,78 @@ static void emit_conditional_select(x86_pre_allocator_context* result, ir_operan
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_d_n_f_d_n_m(x86_pre_allocator_context* result, uint64_t instruction, ir_operand destination, ir_operand source_0, ir_operand source_1)
|
||||
static bool instruction_is_commutative(uint64_t instruction)
|
||||
{
|
||||
switch (instruction)
|
||||
{
|
||||
case ir_add:
|
||||
case ir_multiply:
|
||||
case ir_bitwise_and:
|
||||
case ir_bitwise_or:
|
||||
case ir_bitwise_exclusive_or:
|
||||
{
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void swap(ir_operand* l, ir_operand* r)
|
||||
{
|
||||
ir_operand tmp = *l;
|
||||
|
||||
*l = *r;
|
||||
*r = tmp;
|
||||
}
|
||||
|
||||
static void emit_d_n_f_d_n_m(x86_pre_allocator_context* result, ir_instructions instruction, ir_operand destination, ir_operand source_0, ir_operand source_1)
|
||||
{
|
||||
assert_same_size({ destination, source_0, source_1 });
|
||||
|
||||
if (instruction_is_commutative(instruction) && ir_operand::is_constant(&source_0) && !ir_operand::is_constant(&source_1))
|
||||
{
|
||||
swap(&source_0, &source_1);
|
||||
}
|
||||
|
||||
if ((ir_operand::is_constant(&source_1) && source_1.value < INT32_MAX) && !ir_operand::is_constant(&source_0))
|
||||
{
|
||||
if (!ir_operand::are_equal(destination, source_0))
|
||||
{
|
||||
emit_move(result,destination, source_0);
|
||||
}
|
||||
|
||||
ir_operation_block::emitds(result->ir, instruction, destination, destination, source_1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ir_operand working_destination = destination;
|
||||
ir_operand working_source_0 = register_or_constant(result, &source_0);
|
||||
ir_operand working_source_1 = register_or_constant(result, &source_1);
|
||||
|
||||
ir_operand working_scrap = create_scrap_operand(result, destination.meta_data);
|
||||
if (ir_operand::are_equal(working_destination, working_source_0))
|
||||
{
|
||||
ir_operation_block::emitds(result->ir, instruction, working_destination, working_destination, working_source_1);
|
||||
}
|
||||
else if (instruction == ir_add && ir_operand::get_raw_size(&working_destination) > int16)
|
||||
{
|
||||
ir_operation_block::emitds(result->ir, x86_lea, working_destination, working_source_0, working_source_1);
|
||||
}
|
||||
else if (!ir_operand::are_equal(working_destination, working_source_1))
|
||||
{
|
||||
emit_move(result,destination, source_0);
|
||||
ir_operation_block::emitds(result->ir, instruction, working_destination, working_destination, working_source_1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ir_operand working_scrap = create_scrap_operand(result, destination.meta_data);
|
||||
|
||||
//ins destination source_0 source_1
|
||||
|
||||
//mov scrap source_0
|
||||
emit_move(result, working_scrap, working_source_0);
|
||||
|
||||
//ins scrap source_1
|
||||
ir_operation_block::emitds(result->ir, instruction, working_scrap, working_scrap, working_source_1);
|
||||
|
||||
//mov destination scrap
|
||||
emit_move(result, working_destination, working_scrap);
|
||||
emit_move(result, working_scrap, working_source_0);
|
||||
ir_operation_block::emitds(result->ir, instruction, working_scrap, working_scrap, working_source_1);
|
||||
|
||||
emit_move(result, working_destination, working_scrap);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_floating_point_compare(x86_pre_allocator_context* result, uint64_t instruction, ir_operand destination, ir_operand source_0, ir_operand source_1)
|
||||
@@ -271,6 +323,18 @@ static void emit_shift(x86_pre_allocator_context* result, uint64_t instruction,
|
||||
{
|
||||
assert_same_size({ destination, source_0, source_1 });
|
||||
|
||||
if ((ir_operand::is_constant(&source_1) && source_1.value < 255) && !ir_operand::is_constant(&source_0))
|
||||
{
|
||||
if (!ir_operand::are_equal(destination, source_0))
|
||||
{
|
||||
emit_move(result,destination, source_0);
|
||||
}
|
||||
|
||||
ir_operation_block::emitds(result->ir, instruction, destination, destination, source_1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ir_operand working_destination = destination;
|
||||
ir_operand working_source_0 = register_or_constant(result, &source_0);
|
||||
ir_operand working_source_1 = register_or_constant(result, &source_1);
|
||||
@@ -332,9 +396,14 @@ static void emit_d_f_d_n(x86_pre_allocator_context* result, uint64_t instruction
|
||||
assert_is_register(destination);
|
||||
|
||||
ir_operand working_destination = destination;
|
||||
ir_operand working_source_0 = register_or_constant(result, &source);
|
||||
|
||||
emit_move(result, working_destination, working_source_0);
|
||||
if (!ir_operand::are_equal(destination, source))
|
||||
{
|
||||
ir_operand working_source_0 = register_or_constant(result, &source);
|
||||
|
||||
emit_move(result, working_destination, working_source_0);
|
||||
}
|
||||
|
||||
ir_operation_block::emitds(result->ir, instruction, working_destination, working_destination);
|
||||
}
|
||||
|
||||
@@ -428,20 +497,20 @@ static void emit_big_multiply_divide(x86_pre_allocator_context* result, uint64_t
|
||||
ir_operation_block::emits(result->ir, ir_instructions::ir_register_allocator_p_unlock, ax);
|
||||
}
|
||||
|
||||
static void emit_return(x86_pre_allocator_context* result, ir_operand to_return)
|
||||
static void emit_context_exit(x86_pre_allocator_context* result, uint64_t instruction, ir_operand new_location)
|
||||
{
|
||||
int raw_size = ir_operand::get_raw_size(&to_return);
|
||||
int raw_size = ir_operand::get_raw_size(&new_location);
|
||||
|
||||
to_return = register_or_constant(result, &to_return, raw_size != int64);
|
||||
new_location = register_or_constant(result, &new_location, raw_size != int64);
|
||||
|
||||
to_return.meta_data = int64;
|
||||
new_location.meta_data = int64;
|
||||
|
||||
if (raw_size <= int16)
|
||||
{
|
||||
ir_operation_block::emitds(result->ir,ir_bitwise_and, to_return, to_return, ir_operand::create_con((1 << (8 << raw_size)) - 1));
|
||||
ir_operation_block::emitds(result->ir,ir_bitwise_and, new_location, new_location, ir_operand::create_con((1 << (8 << raw_size)) - 1));
|
||||
}
|
||||
|
||||
ir_operation_block::emits(result->ir, ir_instructions::ir_close_and_return,to_return , ir_operand::create_con(0));
|
||||
ir_operation_block::emits(result->ir, instruction, new_location , ir_operand::create_con(0));
|
||||
|
||||
intrusive_linked_list< intrusive_linked_list_element<ir_operation>*>::insert_element(result->revisit_instructions, result->ir->operations->last->prev);
|
||||
}
|
||||
@@ -512,7 +581,11 @@ static void emit_vector_insert(x86_pre_allocator_context* result, ir_operation*
|
||||
assert_is_constant(index);
|
||||
assert_is_constant(size);
|
||||
|
||||
emit_move(result, destination, source_vector);
|
||||
if (!ir_operand::are_equal(destination, source_vector))
|
||||
{
|
||||
emit_move(result, destination, source_vector);
|
||||
}
|
||||
|
||||
ir_operation_block::emitds(result->ir, ir_vector_insert, destination, destination, value, index, size);
|
||||
}
|
||||
|
||||
@@ -777,10 +850,11 @@ static void emit_pre_allocation_instruction(x86_pre_allocator_context* pre_alloc
|
||||
|
||||
//ABI
|
||||
case ir_close_and_return:
|
||||
case ir_table_jump:
|
||||
{
|
||||
assert_operand_count(operation, 0, 1);
|
||||
|
||||
emit_return(pre_allocator_context, operation->sources[0]);
|
||||
emit_context_exit(pre_allocator_context, working_instruction, operation->sources[0]);
|
||||
|
||||
}; break;
|
||||
|
||||
@@ -985,6 +1059,7 @@ void x86_pre_allocator_context::run_pass(x86_pre_allocator_context* pre_allocato
|
||||
} break;
|
||||
|
||||
case ir_close_and_return:
|
||||
case ir_table_jump:
|
||||
{
|
||||
working_element->data.sources[1].value = context_size;
|
||||
} break;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "aarch64_emit_context.h"
|
||||
#include "emulator/ssa_emit_context.h"
|
||||
#include "emulator/guest_process.h"
|
||||
#include "jit/jit_memory.h"
|
||||
|
||||
void aarch64_emit_context::create(guest_process* process, aarch64_emit_context* result, ssa_emit_context* ssa)
|
||||
{
|
||||
@@ -60,8 +61,41 @@ void aarch64_emit_context::emit_store_context(aarch64_emit_context* ctx)
|
||||
ctx->context_movement.push_back(ir_operation_block::emits(ir, ir_guest_store_context, ctx->context_pointer));
|
||||
}
|
||||
|
||||
void aarch64_emit_context::branch_long(aarch64_emit_context* ctx, ir_operand new_location, bool store_context)
|
||||
{
|
||||
static void table_branch(aarch64_emit_context* ctx, ir_operand address)
|
||||
{
|
||||
guest_process* process = ctx->process;
|
||||
ir_operation_block* ir = ctx->raw_ir;
|
||||
|
||||
auto table = &process->guest_functions.native_function_table;
|
||||
|
||||
if (!fast_function_table::is_open(table))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ir_operand end = ir_operation_block::create_label(ir);
|
||||
|
||||
ir_operand table_base = ir_operand::create_con((uint64_t)table->function_store);
|
||||
|
||||
address = ssa_emit_context::emit_ssa(ctx->ssa, ir_subtract, address, ir_operand::create_con(table->entry_address));
|
||||
|
||||
ir_operation_block::jump_if(ir, end, ssa_emit_context::emit_ssa(ctx->ssa, ir_compare_greater_equal_unsigned, address, ir_operand::create_con(table->function_store_size)));
|
||||
|
||||
ir_operand value_test = ssa_emit_context::emit_ssa(ctx->ssa, ir_load, ssa_emit_context::emit_ssa(ctx->ssa, ir_add, address, table_base), int32);
|
||||
|
||||
ir_operation_block::jump_if(ir, end, ssa_emit_context::emit_ssa(ctx->ssa, ir_compare_equal, value_test, ir_operand::create_con(UINT32_MAX, int32)));
|
||||
|
||||
ir_operand jit_base = ir_operand::create_con((uint64_t)process->host_jit_context->jit_cache.memory->raw_memory_block);
|
||||
|
||||
value_test = ir_operand::copy_new_raw_size(value_test, int64);
|
||||
|
||||
ir_operation_block::emits(ir, ir_table_jump, ssa_emit_context::emit_ssa(ctx->ssa, ir_add, jit_base, value_test));
|
||||
|
||||
ir_operation_block::mark_label(ir, end);
|
||||
}
|
||||
|
||||
void aarch64_emit_context::branch_long(aarch64_emit_context* ctx, ir_operand new_location, bool store_context, bool allow_table_branch)
|
||||
{
|
||||
ctx->branch_state = branch_type::long_branch;
|
||||
|
||||
if (store_context)
|
||||
@@ -69,6 +103,11 @@ void aarch64_emit_context::branch_long(aarch64_emit_context* ctx, ir_operand new
|
||||
emit_store_context(ctx);
|
||||
}
|
||||
|
||||
if (allow_table_branch)
|
||||
{
|
||||
table_branch(ctx, new_location);
|
||||
}
|
||||
|
||||
ir_operation_block::emits(ctx->raw_ir, ir_close_and_return, new_location);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ struct aarch64_emit_context
|
||||
static void init_context(aarch64_emit_context* ctx);
|
||||
static void emit_load_context(aarch64_emit_context* ctx);
|
||||
static void emit_store_context(aarch64_emit_context* ctx);
|
||||
static void branch_long(aarch64_emit_context* ctx, ir_operand new_location, bool store_context = true);
|
||||
static void branch_long(aarch64_emit_context* ctx, ir_operand new_location, bool store_context = true, bool allow_table_branch = true);
|
||||
static void branch_short(aarch64_emit_context* ctx, ir_operand new_location);
|
||||
static void emit_context_movement(aarch64_emit_context* ctx);
|
||||
static ir_operand get_or_create_basic_block_label(aarch64_emit_context* ctx, uint64_t value);
|
||||
|
||||
@@ -170,6 +170,7 @@ void call_supervisor_jit(ssa_emit_context* ctx, uint64_t svc)
|
||||
);
|
||||
|
||||
ir_operation_block::emits(ctx->ir,ir_close_and_return ,ir_operand::create_con(actx->current_instruction_address + 4));
|
||||
|
||||
actx->branch_state = branch_type::long_branch;
|
||||
}
|
||||
|
||||
|
||||
@@ -4054,10 +4054,14 @@ uint64_t FPAdd_interpreter(interpreter_data* ctx, uint64_t operand1, uint64_t op
|
||||
{
|
||||
if (N == 32ULL)
|
||||
{
|
||||
uint32_t o1 = operand1;
|
||||
uint32_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
if (N == 64ULL)
|
||||
{
|
||||
uint64_t o1 = operand1;
|
||||
uint64_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
|
||||
@@ -4071,10 +4075,14 @@ uint64_t FPSub_interpreter(interpreter_data* ctx, uint64_t operand1, uint64_t op
|
||||
{
|
||||
if (N == 32ULL)
|
||||
{
|
||||
uint32_t o1 = operand1;
|
||||
uint32_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
if (N == 64ULL)
|
||||
{
|
||||
uint64_t o1 = operand1;
|
||||
uint64_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
|
||||
@@ -4088,10 +4096,14 @@ uint64_t FPMul_interpreter(interpreter_data* ctx, uint64_t operand1, uint64_t op
|
||||
{
|
||||
if (N == 32ULL)
|
||||
{
|
||||
uint32_t o1 = operand1;
|
||||
uint32_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
if (N == 64ULL)
|
||||
{
|
||||
uint64_t o1 = operand1;
|
||||
uint64_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
|
||||
@@ -4105,10 +4117,14 @@ uint64_t FPDiv_interpreter(interpreter_data* ctx, uint64_t operand1, uint64_t op
|
||||
{
|
||||
if (N == 32ULL)
|
||||
{
|
||||
uint32_t o1 = operand1;
|
||||
uint32_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
if (N == 64ULL)
|
||||
{
|
||||
uint64_t o1 = operand1;
|
||||
uint64_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
|
||||
@@ -4122,10 +4138,14 @@ uint64_t FPMax_interpreter(interpreter_data* ctx, uint64_t operand1, uint64_t op
|
||||
{
|
||||
if (N == 32ULL)
|
||||
{
|
||||
uint32_t o1 = operand1;
|
||||
uint32_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
if (N == 64ULL)
|
||||
{
|
||||
uint64_t o1 = operand1;
|
||||
uint64_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
|
||||
@@ -4139,10 +4159,14 @@ uint64_t FPMin_interpreter(interpreter_data* ctx, uint64_t operand1, uint64_t op
|
||||
{
|
||||
if (N == 32ULL)
|
||||
{
|
||||
uint32_t o1 = operand1;
|
||||
uint32_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
if (N == 64ULL)
|
||||
{
|
||||
uint64_t o1 = operand1;
|
||||
uint64_t o2 = operand2;
|
||||
return (undefined_value());
|
||||
}
|
||||
|
||||
@@ -9683,7 +9707,9 @@ ir_operand FPAdd_jit(ssa_emit_context* ctx, ir_operand operand1, ir_operand oper
|
||||
{
|
||||
uint64_t F = N == 32ULL ? int32 : N == 64ULL ? int64 : 0;
|
||||
{
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_add, copy_new_raw_size(ctx, operand1, F), copy_new_raw_size(ctx, operand2, F)), int64);
|
||||
ir_operand o1 = copy_new_raw_size(ctx, operand1, F);
|
||||
ir_operand o2 = copy_new_raw_size(ctx, operand2, F);
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_add, o1, o2), int64);
|
||||
}
|
||||
}
|
||||
return call_float_binary_jit(ctx,operand1,operand2,FPCR,N,(uint64_t)FPAdd_I);
|
||||
@@ -9695,7 +9721,9 @@ ir_operand FPSub_jit(ssa_emit_context* ctx, ir_operand operand1, ir_operand oper
|
||||
{
|
||||
uint64_t F = N == 32ULL ? int32 : N == 64ULL ? int64 : 0;
|
||||
{
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_subtract, copy_new_raw_size(ctx, operand1, F), copy_new_raw_size(ctx, operand2, F)), int64);
|
||||
ir_operand o1 = copy_new_raw_size(ctx, operand1, F);
|
||||
ir_operand o2 = copy_new_raw_size(ctx, operand2, F);
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_subtract, o1, o2), int64);
|
||||
}
|
||||
}
|
||||
return call_float_binary_jit(ctx,operand1,operand2,FPCR,N,(uint64_t)FPSub_I);
|
||||
@@ -9707,7 +9735,9 @@ ir_operand FPMul_jit(ssa_emit_context* ctx, ir_operand operand1, ir_operand oper
|
||||
{
|
||||
uint64_t F = N == 32ULL ? int32 : N == 64ULL ? int64 : 0;
|
||||
{
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_multiply, copy_new_raw_size(ctx, operand1, F), copy_new_raw_size(ctx, operand2, F)), int64);
|
||||
ir_operand o1 = copy_new_raw_size(ctx, operand1, F);
|
||||
ir_operand o2 = copy_new_raw_size(ctx, operand2, F);
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_multiply, o1, o2), int64);
|
||||
}
|
||||
}
|
||||
return call_float_binary_jit(ctx,operand1,operand2,FPCR,N,(uint64_t)FPMul_I);
|
||||
@@ -9719,7 +9749,9 @@ ir_operand FPDiv_jit(ssa_emit_context* ctx, ir_operand operand1, ir_operand oper
|
||||
{
|
||||
uint64_t F = N == 32ULL ? int32 : N == 64ULL ? int64 : 0;
|
||||
{
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_divide, copy_new_raw_size(ctx, operand1, F), copy_new_raw_size(ctx, operand2, F)), int64);
|
||||
ir_operand o1 = copy_new_raw_size(ctx, operand1, F);
|
||||
ir_operand o2 = copy_new_raw_size(ctx, operand2, F);
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_divide, o1, o2), int64);
|
||||
}
|
||||
}
|
||||
return call_float_binary_jit(ctx,operand1,operand2,FPCR,N,(uint64_t)FPDiv_I);
|
||||
@@ -9731,7 +9763,9 @@ ir_operand FPMax_jit(ssa_emit_context* ctx, ir_operand operand1, ir_operand oper
|
||||
{
|
||||
uint64_t F = N == 32ULL ? int32 : N == 64ULL ? int64 : 0;
|
||||
{
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_select_max, copy_new_raw_size(ctx, operand1, F), copy_new_raw_size(ctx, operand2, F)), int64);
|
||||
ir_operand o1 = copy_new_raw_size(ctx, operand1, F);
|
||||
ir_operand o2 = copy_new_raw_size(ctx, operand2, F);
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_select_max, o1, o2), int64);
|
||||
}
|
||||
}
|
||||
return call_float_binary_jit(ctx,operand1,operand2,FPCR,N,(uint64_t)FPMax_I);
|
||||
@@ -9743,7 +9777,9 @@ ir_operand FPMin_jit(ssa_emit_context* ctx, ir_operand operand1, ir_operand oper
|
||||
{
|
||||
uint64_t F = N == 32ULL ? int32 : N == 64ULL ? int64 : 0;
|
||||
{
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_select_min, copy_new_raw_size(ctx, operand1, F), copy_new_raw_size(ctx, operand2, F)), int64);
|
||||
ir_operand o1 = copy_new_raw_size(ctx, operand1, F);
|
||||
ir_operand o2 = copy_new_raw_size(ctx, operand2, F);
|
||||
return copy_new_raw_size(ctx, ssa_emit_context::emit_ssa(ctx, ir_floating_point_select_min, o1, o2), int64);
|
||||
}
|
||||
}
|
||||
return call_float_binary_jit(ctx,operand1,operand2,FPCR,N,(uint64_t)FPMin_I);
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "fast_function_table.h"
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
|
||||
bool fast_function_table::is_open(fast_function_table* table)
|
||||
{
|
||||
return table->function_store != nullptr;
|
||||
}
|
||||
|
||||
bool fast_function_table::insert_function(fast_function_table* table, uint64_t guest_address, uint32_t jit_offset)
|
||||
{
|
||||
if (!is_open(table))
|
||||
{
|
||||
init(table, guest_address);
|
||||
}
|
||||
|
||||
guest_address -= table->entry_address;
|
||||
|
||||
if (guest_address >= table->function_store_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*(uint32_t*)((uint64_t)table->function_store + guest_address) = jit_offset;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fast_function_table::fast_function_table()
|
||||
{
|
||||
function_store = nullptr;
|
||||
|
||||
entry_address = -1;
|
||||
function_store_size = -1;
|
||||
}
|
||||
|
||||
void fast_function_table::init(fast_function_table* result, uint64_t entry_address)
|
||||
{
|
||||
result->entry_address = entry_address;
|
||||
|
||||
result->function_store_size = 100 * 1024 * 1024;
|
||||
result->function_store = malloc(result->function_store_size);
|
||||
memset(result->function_store, -1, result->function_store_size);
|
||||
}
|
||||
|
||||
void fast_function_table::destroy(fast_function_table* to_destroy)
|
||||
{
|
||||
if (is_open(to_destroy))
|
||||
{
|
||||
free(to_destroy->function_store);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t fast_function_table::request_address(fast_function_table* table, uint64_t guest_address, bool* is_valid)
|
||||
{
|
||||
*is_valid = false;
|
||||
|
||||
if (!is_open(table))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
guest_address -= table->entry_address;
|
||||
|
||||
if (guest_address >= table->function_store_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t working_result = *(uint32_t*)((uint64_t)table->function_store + guest_address);
|
||||
|
||||
*is_valid = working_result != -1;
|
||||
|
||||
return working_result;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef FAST_FUNCTION_TABLE_H
|
||||
#define FAST_FUNCTION_TABLE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
struct fast_function_table
|
||||
{
|
||||
uint64_t entry_address;
|
||||
uint64_t function_store_size;
|
||||
|
||||
void* function_store;
|
||||
|
||||
fast_function_table();
|
||||
|
||||
static bool is_open(fast_function_table* test);
|
||||
static bool insert_function(fast_function_table* table, uint64_t guest_address, uint32_t jit_offset);
|
||||
static void init(fast_function_table* result, uint64_t entry_address);
|
||||
static void destroy(fast_function_table* to_destroy);
|
||||
static uint32_t request_address(fast_function_table* test, uint64_t guest_address, bool* is_valid);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -6,6 +6,7 @@
|
||||
struct guest_function
|
||||
{
|
||||
uint64_t times_executed;
|
||||
uint32_t jit_offset;
|
||||
void (*raw_function)(void* arguments);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,33 @@
|
||||
#include "guest_function_store.h"
|
||||
#include "ir/ir.h"
|
||||
#include "guest_process.h"
|
||||
#include "jit/jit_memory.h"
|
||||
|
||||
guest_function guest_function_store::get_or_translate_function(guest_function_store* context, uint64_t address, translate_request_data* process_context)
|
||||
{
|
||||
auto function_table = &context->native_function_table;
|
||||
|
||||
if (fast_function_table::is_open(function_table))
|
||||
{
|
||||
bool exists;
|
||||
|
||||
uint32_t jit_offset = fast_function_table::request_address(function_table, address, &exists);
|
||||
|
||||
if (exists)
|
||||
{
|
||||
guest_function result;
|
||||
|
||||
result.times_executed = 0;
|
||||
result.jit_offset = jit_offset;
|
||||
|
||||
uint64_t jit_base = (uint64_t)((guest_process*)process_context->process)->host_jit_context->jit_cache.memory->raw_memory_block;
|
||||
|
||||
result.raw_function = (void(*)(void*))(jit_base + jit_offset);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
context->lock.lock();
|
||||
|
||||
if (context->functions.find(address) == context->functions.end())
|
||||
@@ -13,6 +38,11 @@ guest_function guest_function_store::get_or_translate_function(guest_function_st
|
||||
|
||||
context->lock.lock();
|
||||
|
||||
if (context->use_flt)
|
||||
{
|
||||
fast_function_table::insert_function(function_table, address, result.jit_offset);
|
||||
}
|
||||
|
||||
context->functions[address] = result;
|
||||
|
||||
context->lock.unlock();
|
||||
@@ -27,4 +57,9 @@ guest_function guest_function_store::get_or_translate_function(guest_function_st
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void guest_function_store::destroy(guest_function_store* to_destory)
|
||||
{
|
||||
fast_function_table::destroy(&to_destory->native_function_table);
|
||||
}
|
||||
@@ -4,7 +4,9 @@
|
||||
#include <unordered_map>
|
||||
#include <inttypes.h>
|
||||
#include <mutex>
|
||||
|
||||
#include "translate_request_data.h"
|
||||
#include "fast_function_table.h"
|
||||
|
||||
struct guest_function_store;
|
||||
struct translate_request_data;
|
||||
@@ -14,8 +16,11 @@ struct guest_function_store
|
||||
std::mutex lock;
|
||||
std::unordered_map<uint64_t, guest_function> functions;
|
||||
translate_guest_function translate_function_pointer;
|
||||
fast_function_table native_function_table;
|
||||
bool use_flt;
|
||||
|
||||
static guest_function get_or_translate_function(guest_function_store* context, uint64_t address, translate_request_data* process_context);
|
||||
static void destroy(guest_function_store* to_destory);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "aarch64/aarch64_process.h"
|
||||
#include "aarch64/aarch64_impl.h"
|
||||
#include "jit/jit_memory.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
@@ -19,6 +20,7 @@ void guest_process::create(guest_process* result, guest_memory guest_memory_cont
|
||||
result->svc_function = nullptr;
|
||||
result->undefined_instruction = nullptr;
|
||||
result->debug_mode = false;
|
||||
result->guest_functions.use_flt = true;
|
||||
|
||||
init_aarch64_decoder(result);
|
||||
}
|
||||
@@ -118,7 +120,7 @@ guest_function guest_process::translate_function(translate_request_data* data)
|
||||
|
||||
auto instruction_table = fixed_length_decoder<uint32_t>::decode_slow(&process->decoder, raw_instruction);
|
||||
|
||||
ssa_emit_context::reset_local(&ssa_emit);
|
||||
//ssa_emit_context::reset_local(&ssa_emit);
|
||||
|
||||
if (instruction_table == nullptr)
|
||||
{
|
||||
@@ -157,14 +159,13 @@ guest_function guest_process::translate_function(translate_request_data* data)
|
||||
|
||||
aarch64_emit_context::emit_context_movement(&aarch64_emit);
|
||||
|
||||
//ir_operation_block::log(raw_ir);
|
||||
|
||||
void* code = jit_context::compile_code(process->host_jit_context, raw_ir,(compiler_flags)0);
|
||||
void* code = jit_context::compile_code(process->host_jit_context, raw_ir,compiler_flags::optimize_ssa);
|
||||
|
||||
guest_function result;
|
||||
|
||||
result.times_executed = 0;
|
||||
result.raw_function = (void(*)(void*))code;
|
||||
result.jit_offset = (uint64_t)result.raw_function - (uint64_t)process->host_jit_context->jit_cache.memory->raw_memory_block;
|
||||
|
||||
arena_allocator::destroy(&allocator);
|
||||
|
||||
@@ -240,6 +241,8 @@ void guest_process::create(guest_process* result, guest_memory memory, jit_conte
|
||||
|
||||
void guest_process::destroy(guest_process* process)
|
||||
{
|
||||
guest_function_store::destroy(&process->guest_functions);
|
||||
|
||||
switch (process->process_type)
|
||||
{
|
||||
case arm:
|
||||
|
||||
@@ -337,7 +337,7 @@ void basic_register_allocator_context::run_pass(basic_register_allocator_context
|
||||
allocate_registers(result_register_allocator, new_sources, stack_max, working_operation.sources.data, working_operation.sources.count, register_mode::read);
|
||||
allocate_registers(result_register_allocator, new_destinations, stack_max, working_operation.destinations.data, working_operation.destinations.count, register_mode::write);
|
||||
|
||||
if (ir_operation_block::is_label(instruction) || instruction == ir_external_call)
|
||||
if (ir_operation_block::is_flow_critical(instruction) || instruction == ir_external_call)
|
||||
{
|
||||
unlock_all_basic(result_register_allocator);
|
||||
|
||||
|
||||
+5
-1
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "ir.h"
|
||||
#include <vector>
|
||||
#include "debugging.h"
|
||||
|
||||
static void assert_operand_count(ir_operation* operation, int destinations, int sources)
|
||||
{
|
||||
@@ -90,7 +91,10 @@ static void assert_same_size(std::initializer_list<ir_operand> operands)
|
||||
{
|
||||
uint64_t working_size = operands.begin()[i].meta_data & UINT32_MAX;
|
||||
|
||||
assert(working_size == first_size);
|
||||
if (working_size != first_size)
|
||||
{
|
||||
throw_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-5
@@ -84,6 +84,7 @@ enum ir_instructions : uint64_t
|
||||
ir_compare_and_swap,
|
||||
ir_get_argument,
|
||||
ir_external_call,
|
||||
ir_table_jump,
|
||||
|
||||
//Memory
|
||||
ir_load,
|
||||
@@ -94,6 +95,7 @@ enum ir_instructions : uint64_t
|
||||
ir_open_context,
|
||||
ir_register_allocator_p_lock,
|
||||
ir_register_allocator_p_unlock,
|
||||
ir_ssa_phi,
|
||||
|
||||
//Vectors
|
||||
ir_vector_extract,
|
||||
@@ -173,6 +175,17 @@ static std::string instruction_names[] = {
|
||||
"ir_shift_right_signed",
|
||||
"ir_shift_right_unsigned",
|
||||
"ir_subtract",
|
||||
"ir_floating_point_add",
|
||||
"ir_floating_point_subtract",
|
||||
"ir_floating_point_multiply",
|
||||
"ir_floating_point_divide",
|
||||
"ir_floating_point_select_min",
|
||||
"ir_floating_point_select_max",
|
||||
"ir_floating_point_compare_equal",
|
||||
"ir_floating_point_compare_not_equal",
|
||||
"ir_floating_point_compare_less",
|
||||
"ir_floating_point_compare_greater",
|
||||
"ir_floating_point_compare_greater_equal",
|
||||
|
||||
"ir_binary_end",
|
||||
|
||||
@@ -187,6 +200,7 @@ static std::string instruction_names[] = {
|
||||
"ir_logical_not",
|
||||
"ir_convert_to_float_signed",
|
||||
"ir_convert_to_float_unsigned",
|
||||
"ir_floating_point_square_root",
|
||||
|
||||
"ir_unary_end",
|
||||
|
||||
@@ -207,6 +221,7 @@ static std::string instruction_names[] = {
|
||||
"ir_compare_and_swap",
|
||||
"ir_get_argument",
|
||||
"ir_external_call",
|
||||
"ir_table_jump",
|
||||
|
||||
//Memory
|
||||
"ir_load",
|
||||
@@ -217,6 +232,7 @@ static std::string instruction_names[] = {
|
||||
"ir_open_context",
|
||||
"ir_register_allocator_p_lock",
|
||||
"ir_register_allocator_p_unlock",
|
||||
"ir_ssa_phi",
|
||||
|
||||
//Vectors
|
||||
"ir_vector_extract",
|
||||
@@ -227,7 +243,7 @@ static std::string instruction_names[] = {
|
||||
"ir_assert_false",
|
||||
"ir_assert_true",
|
||||
|
||||
//"x86
|
||||
//x86
|
||||
"x86_cqo",
|
||||
"x86_cdq",
|
||||
"x86_cwd",
|
||||
@@ -258,6 +274,11 @@ static std::string instruction_names[] = {
|
||||
"x86_subsd",
|
||||
"x86_subss",
|
||||
|
||||
"x86_sqrtss",
|
||||
"x86_sqrtsd",
|
||||
"x86_sqrtps",
|
||||
"x86_sqrtpd",
|
||||
|
||||
//Emulator Helpers
|
||||
"ir_guest_store_context",
|
||||
"ir_guest_load_context",
|
||||
@@ -305,7 +326,7 @@ struct ir_operand
|
||||
|
||||
struct ir_operation
|
||||
{
|
||||
uint64_t instruction;
|
||||
ir_instructions instruction;
|
||||
fast_array<ir_operand> destinations;
|
||||
fast_array<ir_operand> sources;
|
||||
};
|
||||
@@ -321,9 +342,11 @@ struct ir_operation_block
|
||||
static void create_raw_operation(arena_allocator* allocator, ir_operation* result, uint64_t instruction, int destination_count, int source_count);
|
||||
static void create_vector_gp_remap_scheme(arena_allocator* allocator, std::unordered_map<uint64_t, uint64_t>* remap_store, std::unordered_map<uint64_t, uint64_t>** remap_redirect);
|
||||
static void clamp_operands(ir_operation_block* ir, bool use_bit_register_allocations, int* size_counts = nullptr);
|
||||
|
||||
static bool is_label(uint64_t instruction);
|
||||
static bool is_label(ir_operation* operation);
|
||||
static void ssa_remap(ir_operation_block* ir, std::unordered_map<uint64_t, uint64_t>* remap_data);
|
||||
|
||||
|
||||
static bool is_flow_critical(uint64_t instruction);
|
||||
static bool is_flow_critical(ir_operation* operation);
|
||||
static ir_operand create_label(ir_operation_block* block);
|
||||
static void mark_label(ir_operation_block* block, ir_operand label);
|
||||
static void jump(ir_operation_block* block, ir_operand label);
|
||||
|
||||
@@ -4,14 +4,38 @@ static ir_control_flow_node* create_and_insert_node(intrusive_linked_list<ir_con
|
||||
{
|
||||
ir_control_flow_node* result = arena_allocator::allocate_struct<ir_control_flow_node>(list->allocator);
|
||||
|
||||
intrusive_linked_list<ir_control_flow_node*>::insert_element(list, result);
|
||||
|
||||
result->entry_instruction = first_instruction;
|
||||
result->final_instruction = block_final_instruction;
|
||||
|
||||
intrusive_linked_list<ir_control_flow_node*>::insert_element(list, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool is_label(ir_operation* operation)
|
||||
{
|
||||
switch (operation->instruction)
|
||||
{
|
||||
case ir_mark_label:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_jump(ir_operation* operation)
|
||||
{
|
||||
switch (operation->instruction)
|
||||
{
|
||||
case ir_jump_if:
|
||||
case ir_close_and_return:
|
||||
case ir_table_jump:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void get_linier_nodes(ir_control_flow_graph* result)
|
||||
{
|
||||
ir_operation_block* source_ir = result->source_ir;
|
||||
@@ -22,7 +46,7 @@ static void get_linier_nodes(ir_control_flow_graph* result)
|
||||
{
|
||||
ir_operation working_operation = i->data;
|
||||
|
||||
if (ir_operation_block::is_label(&working_operation))
|
||||
if (is_jump(&working_operation) || (i->next != nullptr && is_label(&i->next->data)))
|
||||
{
|
||||
working_node->final_instruction = i;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ void ir_operation_block::create_raw_operation(arena_allocator* allocator, ir_ope
|
||||
fast_array<ir_operand>::create(allocator, destination_count, &result->destinations);
|
||||
fast_array<ir_operand>::create(allocator, source_count, &result->sources);
|
||||
|
||||
result->instruction = instruction;
|
||||
result->instruction = (ir_instructions)instruction;
|
||||
}
|
||||
|
||||
intrusive_linked_list_element<ir_operation>* ir_operation_block::emit(ir_operation_block* block, ir_operation operation, intrusive_linked_list_element<ir_operation>* point)
|
||||
@@ -140,6 +140,21 @@ void ir_operation_block::clamp_operands(ir_operation_block* ir, bool use_bit_reg
|
||||
}
|
||||
}
|
||||
|
||||
void ir_operation_block::ssa_remap(ir_operation_block* ir, std::unordered_map<uint64_t, uint64_t>* remap_data)
|
||||
{
|
||||
std::unordered_map<uint64_t, uint64_t>* remap_redirection[ir_operand_meta::top];
|
||||
|
||||
for (int i = 0; i < ir_operand_meta::top; ++i)
|
||||
{
|
||||
remap_redirection[i] = remap_data;
|
||||
}
|
||||
|
||||
for (auto i = ir->operations->first; i != ir->operations->last; i = i->next)
|
||||
{
|
||||
remap_operands_operations_impl(remap_redirection, &i->data, false);
|
||||
}
|
||||
}
|
||||
|
||||
intrusive_linked_list_element<ir_operation>* ir_operation_block::emit_with(ir_operation_block* ir, uint64_t instruction, ir_operand* destinations, int destination_count, ir_operand* sources, int source_count, intrusive_linked_list_element<ir_operation>* point)
|
||||
{
|
||||
ir_operation result;
|
||||
@@ -302,7 +317,7 @@ intrusive_linked_list_element<ir_operation>* ir_operation_block::emits(ir_operat
|
||||
return emit(ir, result, point);
|
||||
}
|
||||
|
||||
bool ir_operation_block::is_label(uint64_t instruction)
|
||||
bool ir_operation_block::is_flow_critical(uint64_t instruction)
|
||||
{
|
||||
switch (instruction)
|
||||
{
|
||||
@@ -315,9 +330,9 @@ bool ir_operation_block::is_label(uint64_t instruction)
|
||||
}
|
||||
}
|
||||
|
||||
bool ir_operation_block::is_label(ir_operation* operation)
|
||||
bool ir_operation_block::is_flow_critical(ir_operation* operation)
|
||||
{
|
||||
return ir_operation_block::is_label(operation->instruction);
|
||||
return ir_operation_block::is_flow_critical(operation->instruction);
|
||||
}
|
||||
|
||||
ir_operand ir_operation_block::create_label(ir_operation_block* block)
|
||||
@@ -333,6 +348,8 @@ ir_operand ir_operation_block::create_label(ir_operation_block* block)
|
||||
void ir_operation_block::mark_label(ir_operation_block* block, ir_operand label)
|
||||
{
|
||||
ir_operation_block::emits(block, ir_mark_label, label);
|
||||
|
||||
ir_operation_block::emits(block, ir_no_operation);
|
||||
}
|
||||
|
||||
void ir_operation_block::jump_if(ir_operation_block* block, ir_operand label, ir_operand condition)
|
||||
@@ -394,11 +411,12 @@ std::string get_string(ir_operand value)
|
||||
|
||||
switch (raw_size)
|
||||
{
|
||||
case ir_operand_meta::int8: result += "INT8"; break;
|
||||
case ir_operand_meta::int16: result += "INT16"; break;
|
||||
case ir_operand_meta::int32: result += "INT32"; break;
|
||||
case ir_operand_meta::int64: result += "INT64"; break;
|
||||
case ir_operand_meta::int128: result += "INT128"; break;
|
||||
case ir_operand_meta::int8: result += "INT8"; break;
|
||||
case ir_operand_meta::int16: result += "INT16"; break;
|
||||
case ir_operand_meta::int32: result += "INT32"; break;
|
||||
case ir_operand_meta::int64: result += "INT64"; break;
|
||||
case ir_operand_meta::int128: result += "INT128"; break;
|
||||
case (ir_operand_meta)UINT32_MAX: result += "GENERIC"; break;
|
||||
default: throw_error();
|
||||
}
|
||||
|
||||
|
||||
+506
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user