Added basic loop unrolling. Blocks that end in a JMP, LOOP or conditional branch to a previous instruction in the block will be unrolled up to 10 times.
This commit is contained in:
parent
b35cf7de09
commit
7e099c277e
9 changed files with 594 additions and 148 deletions
|
|
@ -8,19 +8,71 @@
|
|||
extern int has_ea;
|
||||
static ir_data_t ir_block;
|
||||
|
||||
static int codegen_unroll_start, codegen_unroll_count;
|
||||
|
||||
ir_data_t *codegen_ir_init()
|
||||
{
|
||||
ir_block.wr_pos = 0;
|
||||
// pclog("codegen_ir_init %04x:%04x\n", CS,cpu_state.pc);
|
||||
|
||||
codegen_unroll_count = 0;
|
||||
|
||||
return &ir_block;
|
||||
}
|
||||
|
||||
void codegen_ir_set_unroll(int count, int start)
|
||||
{
|
||||
codegen_unroll_count = count;
|
||||
codegen_unroll_start = start;
|
||||
}
|
||||
|
||||
static void duplicate_uop(ir_data_t *ir, uop_t *uop, int offset)
|
||||
{
|
||||
uop_t *new_uop = uop_alloc(ir, uop->type);
|
||||
|
||||
// pclog(" uop type %08x\n", uop->type);
|
||||
if (!ir_reg_is_invalid(uop->src_reg_a))
|
||||
new_uop->src_reg_a = codegen_reg_read(uop->src_reg_a.reg);
|
||||
if (!ir_reg_is_invalid(uop->src_reg_b))
|
||||
new_uop->src_reg_b = codegen_reg_read(uop->src_reg_b.reg);
|
||||
if (!ir_reg_is_invalid(uop->src_reg_c))
|
||||
new_uop->src_reg_c = codegen_reg_read(uop->src_reg_c.reg);
|
||||
if (!ir_reg_is_invalid(uop->dest_reg_a))
|
||||
new_uop->dest_reg_a = codegen_reg_write(uop->dest_reg_a.reg, ir->wr_pos-1);
|
||||
|
||||
new_uop->type = uop->type;
|
||||
new_uop->imm_data = uop->imm_data;
|
||||
new_uop->p = uop->p;
|
||||
new_uop->pc = uop->pc;
|
||||
|
||||
if (uop->jump_dest_uop != -1)
|
||||
{
|
||||
new_uop->jump_dest_uop = uop->jump_dest_uop + offset;
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_ir_compile(ir_data_t *ir, codeblock_t *block)
|
||||
{
|
||||
int jump_target_at_end = -1;
|
||||
int c;
|
||||
|
||||
if (codegen_unroll_count)
|
||||
{
|
||||
int unroll_count;
|
||||
int unroll_end = ir->wr_pos;
|
||||
|
||||
for (unroll_count = 1; unroll_count < codegen_unroll_count; unroll_count++)
|
||||
{
|
||||
int offset = ir->wr_pos - codegen_unroll_start;
|
||||
// pclog("Unroll from %i to %i, offset %i - iteration %i\n", codegen_unroll_start, ir->wr_pos, offset, unroll_count);
|
||||
for (c = codegen_unroll_start; c < unroll_end; c++)
|
||||
{
|
||||
// pclog(" Duplicate uop %i\n", c);
|
||||
duplicate_uop(ir, &ir->uops[c], offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
codegen_reg_mark_as_required();
|
||||
codegen_reg_process_dead_list(ir);
|
||||
block_write_data = codeblock_allocator_get_ptr(block->head_mem_block);
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@
|
|||
|
||||
ir_data_t *codegen_ir_init();
|
||||
|
||||
void codegen_ir_set_unroll(int count, int start);
|
||||
void codegen_ir_compile(ir_data_t *ir, codeblock_t *block);
|
||||
|
|
|
|||
|
|
@ -336,6 +336,7 @@ typedef struct uop_t
|
|||
int jump_dest_uop;
|
||||
int jump_list_next;
|
||||
void *jump_dest;
|
||||
uint32_t pc;
|
||||
} uop_t;
|
||||
|
||||
#define UOP_NR_MAX 4096
|
||||
|
|
@ -361,6 +362,9 @@ static inline uop_t *uop_alloc(ir_data_t *ir, uint32_t uop_type)
|
|||
uop->src_reg_b = invalid_ir_reg;
|
||||
uop->src_reg_c = invalid_ir_reg;
|
||||
|
||||
uop->pc = cpu_state.oldpc;
|
||||
|
||||
uop->jump_dest_uop = -1;
|
||||
uop->jump_list_next = -1;
|
||||
|
||||
if (uop_type & (UOP_TYPE_BARRIER | UOP_TYPE_ORDER_BARRIER))
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ static int VF_SET_01()
|
|||
return VF_SET() ? 1 : 0;
|
||||
}
|
||||
|
||||
static void ropJO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ static void ropJO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
{
|
||||
case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32:
|
||||
/*Overflow is always zero*/
|
||||
return;
|
||||
return 0;
|
||||
|
||||
case FLAGS_SUB8: case FLAGS_DEC8:
|
||||
jump_uop = uop_CMP_JNO_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
|
|
@ -50,8 +50,9 @@ static void ropJO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 0;
|
||||
}
|
||||
static void ropJNO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJNO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
|
||||
|
|
@ -61,7 +62,7 @@ static void ropJNO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
/*Overflow is always zero*/
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
return;
|
||||
return 0;
|
||||
|
||||
case FLAGS_SUB8: case FLAGS_DEC8:
|
||||
jump_uop = uop_CMP_JO_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
|
|
@ -84,43 +85,59 @@ static void ropJNO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ropJB_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJB_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
int do_unroll = (CF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr));
|
||||
|
||||
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
||||
{
|
||||
case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32:
|
||||
/*Carry is always zero*/
|
||||
return;
|
||||
return 0;
|
||||
|
||||
case FLAGS_SUB8:
|
||||
jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
else
|
||||
jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
break;
|
||||
|
||||
case FLAGS_SUB16:
|
||||
jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
else
|
||||
jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
break;
|
||||
|
||||
case FLAGS_SUB32:
|
||||
jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
else
|
||||
jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
break;
|
||||
|
||||
case FLAGS_UNKNOWN:
|
||||
default:
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
else
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
break;
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return do_unroll ? 1 : 0;
|
||||
}
|
||||
static void ropJNB_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJNB_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
int do_unroll = (!CF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr));
|
||||
|
||||
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
||||
{
|
||||
|
|
@ -128,140 +145,266 @@ static void ropJNB_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
/*Carry is always zero*/
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
return;
|
||||
return 0;
|
||||
|
||||
case FLAGS_SUB8:
|
||||
jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
else
|
||||
jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
break;
|
||||
|
||||
case FLAGS_SUB16:
|
||||
jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
else
|
||||
jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
break;
|
||||
|
||||
case FLAGS_SUB32:
|
||||
jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
else
|
||||
jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
break;
|
||||
|
||||
case FLAGS_UNKNOWN:
|
||||
default:
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET);
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
else
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
break;
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return do_unroll ? 1 : 0;
|
||||
}
|
||||
|
||||
static void ropJE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
|
||||
if (!codegen_flags_changed || (cpu_state.flags_op == FLAGS_UNKNOWN))
|
||||
if (ZF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr))
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
if (!codegen_flags_changed || (cpu_state.flags_op == FLAGS_UNKNOWN))
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0);
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, next_pc);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0);
|
||||
if (!codegen_flags_changed || (cpu_state.flags_op == FLAGS_UNKNOWN))
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0);
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 0;
|
||||
}
|
||||
void ropJNE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
int ropJNE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
|
||||
if (!codegen_flags_changed || (cpu_state.flags_op == FLAGS_UNKNOWN))
|
||||
if (!ZF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr))
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
if (!codegen_flags_changed || (cpu_state.flags_op == FLAGS_UNKNOWN))
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0);
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, next_pc);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0);
|
||||
if (!codegen_flags_changed || (cpu_state.flags_op == FLAGS_UNKNOWN))
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0);
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ropJBE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJBE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop, jump_uop2 = -1;
|
||||
int do_unroll = ((CF_SET() || ZF_SET()) && codegen_can_unroll(block, ir, next_pc, dest_addr));
|
||||
|
||||
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
||||
{
|
||||
case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32:
|
||||
/*Carry is always zero, so test zero only*/
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0);
|
||||
else
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0);
|
||||
break;
|
||||
|
||||
case FLAGS_SUB8:
|
||||
jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
else
|
||||
jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
break;
|
||||
case FLAGS_SUB16:
|
||||
jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
else
|
||||
jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
break;
|
||||
case FLAGS_SUB32:
|
||||
jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
else
|
||||
jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
break;
|
||||
|
||||
case FLAGS_UNKNOWN:
|
||||
default:
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
if (do_unroll)
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
if (do_unroll)
|
||||
{
|
||||
uop_MOV_IMM(ir, IREG_pc, next_pc);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static void ropJNBE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJNBE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop, jump_uop2 = -1;
|
||||
int do_unroll = ((!CF_SET() && !ZF_SET()) && codegen_can_unroll(block, ir, next_pc, dest_addr));
|
||||
|
||||
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
||||
{
|
||||
case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32:
|
||||
/*Carry is always zero, so test zero only*/
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0);
|
||||
else
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0);
|
||||
break;
|
||||
|
||||
case FLAGS_SUB8:
|
||||
jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
else
|
||||
jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
break;
|
||||
case FLAGS_SUB16:
|
||||
jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
else
|
||||
jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
break;
|
||||
case FLAGS_SUB32:
|
||||
jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
else
|
||||
jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
break;
|
||||
|
||||
case FLAGS_UNKNOWN:
|
||||
default:
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET);
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
if (do_unroll)
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET);
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
if (do_unroll)
|
||||
{
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
uop_MOV_IMM(ir, IREG_pc, next_pc);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ropJS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
int do_unroll = (NF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr));
|
||||
|
||||
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
||||
{
|
||||
|
|
@ -273,7 +416,10 @@ static void ropJS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
case FLAGS_SAR8:
|
||||
case FLAGS_INC8:
|
||||
case FLAGS_DEC8:
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B);
|
||||
else
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B);
|
||||
break;
|
||||
|
||||
case FLAGS_ZN16:
|
||||
|
|
@ -284,7 +430,10 @@ static void ropJS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
case FLAGS_SAR16:
|
||||
case FLAGS_INC16:
|
||||
case FLAGS_DEC16:
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W);
|
||||
else
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W);
|
||||
break;
|
||||
|
||||
case FLAGS_ZN32:
|
||||
|
|
@ -295,22 +444,30 @@ static void ropJS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
case FLAGS_SAR32:
|
||||
case FLAGS_INC32:
|
||||
case FLAGS_DEC32:
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res);
|
||||
else
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res);
|
||||
break;
|
||||
|
||||
case FLAGS_UNKNOWN:
|
||||
default:
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
else
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
break;
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return do_unroll ? 1 : 0;
|
||||
}
|
||||
static void ropJNS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJNS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
int do_unroll = (!NF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr));
|
||||
|
||||
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
||||
{
|
||||
|
|
@ -322,7 +479,10 @@ static void ropJNS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
case FLAGS_SAR8:
|
||||
case FLAGS_INC8:
|
||||
case FLAGS_DEC8:
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B);
|
||||
else
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B);
|
||||
break;
|
||||
|
||||
case FLAGS_ZN16:
|
||||
|
|
@ -333,7 +493,10 @@ static void ropJNS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
case FLAGS_SAR16:
|
||||
case FLAGS_INC16:
|
||||
case FLAGS_DEC16:
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W);
|
||||
else
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W);
|
||||
break;
|
||||
|
||||
case FLAGS_ZN32:
|
||||
|
|
@ -344,21 +507,28 @@ static void ropJNS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
case FLAGS_SAR32:
|
||||
case FLAGS_INC32:
|
||||
case FLAGS_DEC32:
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res);
|
||||
else
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res);
|
||||
break;
|
||||
|
||||
case FLAGS_UNKNOWN:
|
||||
default:
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET);
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
|
||||
else
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
break;
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return do_unroll ? 1 : 0;
|
||||
}
|
||||
|
||||
static void ropJP_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJP_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
|
||||
|
|
@ -367,8 +537,9 @@ static void ropJP_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 0;
|
||||
}
|
||||
static void ropJNP_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJNP_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
|
||||
|
|
@ -377,146 +548,267 @@ static void ropJNP_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
|||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ropJL_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJL_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
int do_unroll = ((NF_SET() ? 1 : 0) != (VF_SET() ? 1 : 0) && codegen_can_unroll(block, ir, next_pc, dest_addr));
|
||||
|
||||
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
||||
{
|
||||
case FLAGS_ZN8:
|
||||
/*V flag is always clear. Condition is true if N is set*/
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B);
|
||||
else
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B);
|
||||
break;
|
||||
case FLAGS_ZN16:
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W);
|
||||
else
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W);
|
||||
break;
|
||||
case FLAGS_ZN32:
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res);
|
||||
else
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res);
|
||||
break;
|
||||
|
||||
case FLAGS_SUB8: case FLAGS_DEC8:
|
||||
jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
else
|
||||
jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
break;
|
||||
case FLAGS_SUB16: case FLAGS_DEC16:
|
||||
jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
else
|
||||
jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
break;
|
||||
case FLAGS_SUB32: case FLAGS_DEC32:
|
||||
jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
else
|
||||
jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
break;
|
||||
|
||||
case FLAGS_UNKNOWN:
|
||||
default:
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01);
|
||||
jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
else
|
||||
jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
break;
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
if (do_unroll)
|
||||
uop_MOV_IMM(ir, IREG_pc, next_pc);
|
||||
else
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return do_unroll ? 1 : 0;
|
||||
}
|
||||
static void ropJNL_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJNL_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop;
|
||||
|
||||
int do_unroll = ((NF_SET() ? 1 : 0) == (VF_SET() ? 1 : 0) && codegen_can_unroll(block, ir, next_pc, dest_addr));
|
||||
|
||||
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
||||
{
|
||||
case FLAGS_ZN8:
|
||||
/*V flag is always clear. Condition is true if N is set*/
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B);
|
||||
else
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B);
|
||||
break;
|
||||
case FLAGS_ZN16:
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W);
|
||||
else
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W);
|
||||
break;
|
||||
case FLAGS_ZN32:
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res);
|
||||
else
|
||||
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res);
|
||||
break;
|
||||
|
||||
case FLAGS_SUB8: case FLAGS_DEC8:
|
||||
jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
else
|
||||
jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
break;
|
||||
case FLAGS_SUB16: case FLAGS_DEC16:
|
||||
jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
else
|
||||
jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
break;
|
||||
case FLAGS_SUB32: case FLAGS_DEC32:
|
||||
jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
else
|
||||
jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
break;
|
||||
|
||||
case FLAGS_UNKNOWN:
|
||||
default:
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01);
|
||||
jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
else
|
||||
jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
break;
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
if (do_unroll)
|
||||
uop_MOV_IMM(ir, IREG_pc, next_pc);
|
||||
else
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return do_unroll ? 1 : 0;
|
||||
}
|
||||
|
||||
static void ropJLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop, jump_uop2 = -1;
|
||||
int do_unroll = (((NF_SET() ? 1 : 0) != (VF_SET() ? 1 : 0) || ZF_SET()) && codegen_can_unroll(block, ir, next_pc, dest_addr));
|
||||
|
||||
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
||||
{
|
||||
case FLAGS_SUB8: case FLAGS_DEC8:
|
||||
jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
else
|
||||
jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
break;
|
||||
case FLAGS_SUB16: case FLAGS_DEC16:
|
||||
jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
else
|
||||
jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
break;
|
||||
case FLAGS_SUB32: case FLAGS_DEC32:
|
||||
jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
else
|
||||
jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
break;
|
||||
|
||||
case FLAGS_UNKNOWN:
|
||||
default:
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01);
|
||||
jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
if (do_unroll)
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01);
|
||||
jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01);
|
||||
jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
if (do_unroll)
|
||||
{
|
||||
uop_MOV_IMM(ir, IREG_pc, next_pc);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static void ropJNLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr)
|
||||
static int ropJNLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc)
|
||||
{
|
||||
int jump_uop, jump_uop2 = -1;
|
||||
int do_unroll = ((NF_SET() ? 1 : 0) == (VF_SET() ? 1 : 0) && !ZF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr));
|
||||
|
||||
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
||||
{
|
||||
case FLAGS_SUB8: case FLAGS_DEC8:
|
||||
jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
else
|
||||
jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
|
||||
break;
|
||||
case FLAGS_SUB16: case FLAGS_DEC16:
|
||||
jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
else
|
||||
jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
|
||||
break;
|
||||
case FLAGS_SUB32: case FLAGS_DEC32:
|
||||
jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
if (do_unroll)
|
||||
jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
else
|
||||
jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1, IREG_flags_op2);
|
||||
break;
|
||||
|
||||
case FLAGS_UNKNOWN:
|
||||
default:
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01);
|
||||
jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
if (do_unroll)
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01);
|
||||
jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
|
||||
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01);
|
||||
uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01);
|
||||
jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
if (do_unroll)
|
||||
{
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
uop_MOV_IMM(ir, IREG_pc, next_pc);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
if (jump_uop2 != -1)
|
||||
uop_set_jump_dest(ir, jump_uop2);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define ropJ(cond) \
|
||||
|
|
@ -524,33 +816,36 @@ uint32_t ropJ ## cond ## _8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, u
|
|||
{ \
|
||||
uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); \
|
||||
uint32_t dest_addr = op_pc + 1 + offset; \
|
||||
int ret; \
|
||||
\
|
||||
if (!(op_32 & 0x100)) \
|
||||
dest_addr &= 0xffff; \
|
||||
ropJ ## cond ## _common(block, ir, dest_addr); \
|
||||
ret = ropJ ## cond ## _common(block, ir, dest_addr, op_pc+1); \
|
||||
\
|
||||
codegen_mark_code_present(block, cs+op_pc, 1); \
|
||||
return op_pc+1; \
|
||||
return ret ? dest_addr : (op_pc+1); \
|
||||
} \
|
||||
uint32_t ropJ ## cond ## _16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \
|
||||
{ \
|
||||
uint32_t offset = (int32_t)(int16_t)fastreadw(cs + op_pc); \
|
||||
uint32_t dest_addr = (op_pc + 2 + offset) & 0xffff; \
|
||||
int ret; \
|
||||
\
|
||||
ropJ ## cond ## _common(block, ir, dest_addr); \
|
||||
ret = ropJ ## cond ## _common(block, ir, dest_addr, op_pc+2); \
|
||||
\
|
||||
codegen_mark_code_present(block, cs+op_pc, 2); \
|
||||
return op_pc+2; \
|
||||
return ret ? dest_addr : (op_pc+2); \
|
||||
} \
|
||||
uint32_t ropJ ## cond ## _32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \
|
||||
{ \
|
||||
uint32_t offset = fastreadl(cs + op_pc); \
|
||||
uint32_t dest_addr = op_pc + 4 + offset; \
|
||||
int ret; \
|
||||
\
|
||||
ropJ ## cond ## _common(block, ir, dest_addr); \
|
||||
ret = ropJ ## cond ## _common(block, ir, dest_addr, op_pc+4); \
|
||||
\
|
||||
codegen_mark_code_present(block, cs+op_pc, 4); \
|
||||
return op_pc+4; \
|
||||
return ret ? dest_addr : (op_pc+4); \
|
||||
}
|
||||
|
||||
ropJ(O)
|
||||
|
|
@ -596,27 +891,48 @@ uint32_t ropLOOP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet
|
|||
{
|
||||
uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc);
|
||||
uint32_t dest_addr = op_pc + 1 + offset;
|
||||
uint32_t ret_addr;
|
||||
int jump_uop;
|
||||
|
||||
if (!(op_32 & 0x100))
|
||||
dest_addr &= 0xffff;
|
||||
|
||||
if (op_32 & 0x200)
|
||||
if (((op_32 & 0x200) ? ECX : CX) != 1 && codegen_can_unroll(block, ir, op_pc+1, dest_addr))
|
||||
{
|
||||
uop_SUB_IMM(ir, IREG_ECX, IREG_ECX, 1);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_ECX, 0);
|
||||
if (op_32 & 0x200)
|
||||
{
|
||||
uop_SUB_IMM(ir, IREG_ECX, IREG_ECX, 1);
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_ECX, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uop_SUB_IMM(ir, IREG_CX, IREG_CX, 1);
|
||||
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_CX, 0);
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, op_pc+1);
|
||||
ret_addr = dest_addr;
|
||||
CPU_BLOCK_END();
|
||||
}
|
||||
else
|
||||
{
|
||||
uop_SUB_IMM(ir, IREG_CX, IREG_CX, 1);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_CX, 0);
|
||||
if (op_32 & 0x200)
|
||||
{
|
||||
uop_SUB_IMM(ir, IREG_ECX, IREG_ECX, 1);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_ECX, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uop_SUB_IMM(ir, IREG_CX, IREG_CX, 1);
|
||||
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_CX, 0);
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
ret_addr = op_pc+1;
|
||||
}
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
uop_JMP(ir, codegen_exit_rout);
|
||||
uop_set_jump_dest(ir, jump_uop);
|
||||
|
||||
codegen_mark_code_present(block, cs+op_pc, 1);
|
||||
return op_pc+1;
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
uint32_t ropLOOPE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "x86.h"
|
||||
#include "386_common.h"
|
||||
#include "codegen.h"
|
||||
#include "codegen_ir.h"
|
||||
#include "codegen_ir_defs.h"
|
||||
#include "codegen_reg.h"
|
||||
#include "codegen_ops_helpers.h"
|
||||
|
|
@ -24,3 +25,47 @@ void LOAD_IMMEDIATE_FROM_RAM_32_unaligned(codeblock_t *block, ir_data_t *ir, int
|
|||
uop_SHL_IMM(ir, IREG_temp3, IREG_temp3, (4 - (addr & 3)) * 8);
|
||||
uop_OR(ir, dest_reg, dest_reg, IREG_temp3);
|
||||
}
|
||||
|
||||
#define UNROLL_MAX_REG_REFERENCES 200
|
||||
#define UNROLL_MAX_UOPS 1000
|
||||
#define UNROLL_MAX_COUNT 10
|
||||
int codegen_can_unroll_full(codeblock_t *block, ir_data_t *ir, uint32_t next_pc, uint32_t dest_addr)
|
||||
{
|
||||
int start;
|
||||
int max_unroll;
|
||||
|
||||
/*Check that dest instruction was actually compiled into block*/
|
||||
for (start = 0; start < ir->wr_pos; start++)
|
||||
{
|
||||
// pclog(" uOP %i %08x %08x\n", c, ir->uops[c].pc, dest_addr);
|
||||
if (ir->uops[start].pc == dest_addr)
|
||||
break;
|
||||
if (ir->uops[start].pc > dest_addr)
|
||||
{
|
||||
// pclog("Went past dest_addr. start_pc=%08x end_pc=%08x dest_pc=%08x wr_pos=%i loop_size=%i\n", block->pc-cs, next_pc, dest_addr, ir->wr_pos, ir->wr_pos-start);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*Couldn't find any uOPs corresponding to the destination instruction*/
|
||||
if (start == ir->wr_pos)
|
||||
{
|
||||
/*Is instruction jumping to itself?*/
|
||||
if (dest_addr != cpu_state.oldpc)
|
||||
{
|
||||
// pclog("Couldn't find start. start_pc=%08x end_pc=%08x dest_pc=%08x wr_pos=%i loop_size=%i\n", block->pc-cs, next_pc, dest_addr, ir->wr_pos, ir->wr_pos-start);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
max_unroll = UNROLL_MAX_UOPS / ((ir->wr_pos-start)+6);
|
||||
if (max_unroll > (UNROLL_MAX_REG_REFERENCES / max_version_refcount))
|
||||
max_unroll = (UNROLL_MAX_REG_REFERENCES / max_version_refcount);
|
||||
if (max_unroll > UNROLL_MAX_COUNT)
|
||||
max_unroll = UNROLL_MAX_COUNT;
|
||||
if (max_unroll <= 1)
|
||||
return 0;
|
||||
|
||||
codegen_ir_set_unroll(max_unroll, start);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,3 +109,18 @@ static inline void LOAD_IMMEDIATE_FROM_RAM_32(codeblock_t *block, ir_data_t *ir,
|
|||
else
|
||||
uop_MOV_REG_PTR(ir, dest_reg, get_ram_ptr(addr));
|
||||
}
|
||||
|
||||
int codegen_can_unroll_full(codeblock_t *block, ir_data_t *ir, uint32_t next_pc, uint32_t dest_addr);
|
||||
static inline int codegen_can_unroll(codeblock_t *block, ir_data_t *ir, uint32_t next_pc, uint32_t dest_addr)
|
||||
{
|
||||
if (block->flags & CODEBLOCK_BYTE_MASK)
|
||||
return 0;
|
||||
|
||||
/*Is dest within block?*/
|
||||
if (dest_addr > next_pc)
|
||||
return 0;
|
||||
if ((cs+dest_addr) < block->pc)
|
||||
return 0;
|
||||
|
||||
return codegen_can_unroll_full(block, ir, next_pc, dest_addr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,10 @@ uint32_t ropJMP_r8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t f
|
|||
if (!(op_32 & 0x100))
|
||||
dest_addr &= 0xffff;
|
||||
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
if (offset < 0)
|
||||
codegen_can_unroll(block, ir, op_pc+1, dest_addr);
|
||||
codegen_mark_code_present(block, cs+op_pc, 1);
|
||||
return -1;
|
||||
return dest_addr;
|
||||
}
|
||||
uint32_t ropJMP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
|
||||
{
|
||||
|
|
@ -27,18 +28,20 @@ uint32_t ropJMP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t
|
|||
|
||||
dest_addr &= 0xffff;
|
||||
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
if (offset < 0)
|
||||
codegen_can_unroll(block, ir, op_pc+1, dest_addr);
|
||||
codegen_mark_code_present(block, cs+op_pc, 2);
|
||||
return -1;
|
||||
return dest_addr;
|
||||
}
|
||||
uint32_t ropJMP_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
|
||||
{
|
||||
uint32_t offset = fastreadl(cs + op_pc);
|
||||
uint32_t dest_addr = op_pc+4+offset;
|
||||
|
||||
uop_MOV_IMM(ir, IREG_pc, dest_addr);
|
||||
if (offset < 0)
|
||||
codegen_can_unroll(block, ir, op_pc+1, dest_addr);
|
||||
codegen_mark_code_present(block, cs+op_pc, 4);
|
||||
return -1;
|
||||
return dest_addr;
|
||||
}
|
||||
|
||||
uint32_t ropJMP_far_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "codegen_ir_defs.h"
|
||||
#include "codegen_reg.h"
|
||||
|
||||
int max_version_refcount;
|
||||
uint16_t reg_dead_list = 0;
|
||||
|
||||
uint8_t reg_last_version[IREG_COUNT];
|
||||
|
|
@ -249,11 +250,7 @@ void codegen_reg_reset()
|
|||
}
|
||||
|
||||
reg_dead_list = 0;
|
||||
}
|
||||
|
||||
static inline int ir_reg_is_invalid(ir_reg_t ir_reg)
|
||||
{
|
||||
return (IREG_GET_REG(ir_reg.reg) == IREG_INVALID);
|
||||
max_version_refcount = 0;
|
||||
}
|
||||
|
||||
static inline int ir_get_refcount(ir_reg_t ir_reg)
|
||||
|
|
|
|||
|
|
@ -315,7 +315,10 @@ extern ir_reg_t invalid_ir_reg;
|
|||
|
||||
typedef uint16_t ir_host_reg_t;
|
||||
|
||||
extern int max_version_refcount;
|
||||
|
||||
#define REG_VERSION_MAX 250
|
||||
#define REG_REFCOUNT_MAX 250
|
||||
|
||||
static inline ir_reg_t codegen_reg_read(int reg)
|
||||
{
|
||||
|
|
@ -332,8 +335,10 @@ static inline ir_reg_t codegen_reg_read(int reg)
|
|||
version->refcount++;
|
||||
if (!version->refcount)
|
||||
fatal("codegen_reg_read - refcount overflow\n");
|
||||
else if (version->refcount > REG_VERSION_MAX)
|
||||
else if (version->refcount > REG_REFCOUNT_MAX)
|
||||
CPU_BLOCK_END();
|
||||
if (version->refcount > max_version_refcount)
|
||||
max_version_refcount = version->refcount;
|
||||
// pclog("codegen_reg_read: %i %i %i\n", reg & IREG_REG_MASK, ireg.version, reg_version_refcount[IREG_GET_REG(ireg.reg)][ireg.version]);
|
||||
return ireg;
|
||||
}
|
||||
|
|
@ -359,6 +364,9 @@ static inline ir_reg_t codegen_reg_write(int reg, int uop_nr)
|
|||
fatal("codegen_reg_write - version overflow\n");
|
||||
else if (reg_last_version[IREG_GET_REG(reg)] > REG_VERSION_MAX)
|
||||
CPU_BLOCK_END();
|
||||
if (reg_last_version[IREG_GET_REG(reg)] > max_version_refcount)
|
||||
max_version_refcount = reg_last_version[IREG_GET_REG(reg)];
|
||||
|
||||
version = ®_version[IREG_GET_REG(reg)][ireg.version];
|
||||
version->refcount = 0;
|
||||
version->flags = 0;
|
||||
|
|
@ -367,6 +375,11 @@ static inline ir_reg_t codegen_reg_write(int reg, int uop_nr)
|
|||
return ireg;
|
||||
}
|
||||
|
||||
static inline int ir_reg_is_invalid(ir_reg_t ir_reg)
|
||||
{
|
||||
return (IREG_GET_REG(ir_reg.reg) == IREG_INVALID);
|
||||
}
|
||||
|
||||
struct ir_data_t;
|
||||
|
||||
void codegen_reg_reset();
|
||||
|
|
|
|||
Loading…
Reference in a new issue