Added recompiled versions of Jcc, JCXZ, LOOP, LOOPE and LOOPNE.

This commit is contained in:
SarahW 2018-08-30 22:26:33 +01:00
commit 3332897886
18 changed files with 3234 additions and 21 deletions

View file

@ -31,6 +31,19 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val)
#define COND_EQ (0x0)
#define COND_NE (0x1)
#define COND_CS (0x2)
#define COND_CC (0x3)
#define COND_MI (0x4)
#define COND_PL (0x5)
#define COND_VS (0x6)
#define COND_VC (0x7)
#define COND_HI (0x8)
#define COND_LS (0x9)
#define COND_GE (0xa)
#define COND_LT (0xb)
#define COND_GT (0xc)
#define COND_LE (0xd)
#define OPCODE_SHIFT 24
#define OPCODE_ADD_IMM (0x11 << OPCODE_SHIFT)
@ -72,6 +85,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val)
#define OPCODE_AND_LSL (0x050 << 21)
#define OPCODE_AND_ROR (0x056 << 21)
#define OPCODE_ANDS_LSL (0x350 << 21)
#define OPCODE_CMP_LSL (0x358 << 21)
#define OPCODE_EOR_LSL (0x250 << 21)
#define OPCODE_ORR_ASR (0x154 << 21)
#define OPCODE_ORR_LSL (0x150 << 21)
@ -83,6 +97,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val)
#define OPCODE_ASR (0x1ac02800)
#define OPCODE_BLR (0xd63f0000)
#define OPCODE_BR (0xd61f0000)
#define OPCODE_LDR_REG (0xb8606800)
#define OPCODE_LDRB_REG (0x38606800)
#define OPCODE_LDRH_REG (0x78606800)
@ -290,15 +305,75 @@ void host_arm64_BLR(codeblock_t *block, int addr_reg)
codegen_addlong(block, OPCODE_BLR | Rn(addr_reg));
}
uint32_t *host_arm64_BCC_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_CC);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BCS_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_CS);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BEQ_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_EQ);
return &block->data[block_pos-4];
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BGE_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_GE);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BGT_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_GT);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BHI_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_HI);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BLE_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_LE);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BLS_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_LS);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BLT_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_LT);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BMI_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_MI);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BNE_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_NE);
return &block->data[block_pos-4];
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BPL_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_PL);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BVC_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_VC);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_arm64_BVS_(codeblock_t *block)
{
codegen_addlong(block, OPCODE_BCOND | COND_VS);
return (uint32_t *)&block->data[block_pos-4];
}
void host_arm64_branch_set_offset(uint32_t *opcode, void *dest)
@ -307,6 +382,11 @@ void host_arm64_branch_set_offset(uint32_t *opcode, void *dest)
*opcode |= OFFSET19(offset);
}
void host_arm64_BR(codeblock_t *block, int addr_reg)
{
codegen_addlong(block, OPCODE_BR | Rn(addr_reg));
}
void host_arm64_BEQ(codeblock_t *block, void *dest)
{
uint32_t *opcode = host_arm64_BEQ_(block);
@ -375,6 +455,11 @@ void host_arm64_CMPX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data)
fatal("CMPX_IMM %08x\n", imm_data);
}
void host_arm64_CMP_REG_LSL(codeblock_t *block, int src_n_reg, int src_m_reg, int shift)
{
codegen_addlong(block, OPCODE_CMP_LSL | Rd(0x1f) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift));
}
void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data)
{
if (imm_data == 0xffff) /*Quick hack until proper immediate generation is written */
@ -649,6 +734,13 @@ void host_arm64_call(codeblock_t *block, void *dst_addr)
host_arm64_BLR(block, REG_X16);
}
void host_arm64_jump(codeblock_t *block, uintptr_t dst_addr)
{
int offset = add_literal_q(block, (uintptr_t)dst_addr);
host_arm64_LDR_LITERAL_X(block, REG_X16, offset);
host_arm64_BR(block, REG_X16);
}
void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data)
{
if (imm_is_imm16(imm_data))

View file

@ -17,11 +17,25 @@ void host_arm64_BLR(codeblock_t *block, int addr_reg);
void host_arm64_BEQ(codeblock_t *block, void *dest);
uint32_t *host_arm64_BCC_(codeblock_t *block);
uint32_t *host_arm64_BCS_(codeblock_t *block);
uint32_t *host_arm64_BEQ_(codeblock_t *block);
uint32_t *host_arm64_BGE_(codeblock_t *block);
uint32_t *host_arm64_BGT_(codeblock_t *block);
uint32_t *host_arm64_BHI_(codeblock_t *block);
uint32_t *host_arm64_BLE_(codeblock_t *block);
uint32_t *host_arm64_BLS_(codeblock_t *block);
uint32_t *host_arm64_BLT_(codeblock_t *block);
uint32_t *host_arm64_BMI_(codeblock_t *block);
uint32_t *host_arm64_BNE_(codeblock_t *block);
uint32_t *host_arm64_BPL_(codeblock_t *block);
uint32_t *host_arm64_BVC_(codeblock_t *block);
uint32_t *host_arm64_BVS_(codeblock_t *block);
void host_arm64_branch_set_offset(uint32_t *opcode, void *dest);
void host_arm64_BR(codeblock_t *block, int addr_reg);
void host_arm64_CBNZ(codeblock_t *block, int reg, uintptr_t dest);
void host_arm64_CMN_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data);
@ -30,6 +44,8 @@ void host_arm64_CMNX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data);
void host_arm64_CMP_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data);
void host_arm64_CMPX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data);
#define host_arm64_CMP_REG(block, src_n_reg, src_m_reg) host_arm64_CMP_REG_LSL(block, src_n_reg, src_m_reg, 0)
void host_arm64_CMP_REG_LSL(codeblock_t *block, int src_n_reg, int src_m_reg, int shift);
void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data);
void host_arm64_EOR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift);
@ -88,6 +104,7 @@ void host_arm64_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int
void host_arm64_UBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width);
void host_arm64_call(codeblock_t *block, void *dst_addr);
void host_arm64_jump(codeblock_t *block, uintptr_t dst_addr);
void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data);

View file

@ -7,6 +7,8 @@
#include "codegen_backend_arm64_ops.h"
#include "codegen_ir_defs.h"
#define OFFSET19(offset) (((offset >> 2) << 5) & 0x00ffffe0)
#define HOST_REG_GET(reg) (IREG_GET_REG(reg) & 0x1f)
#define REG_IS_L(size) (size == IREG_SIZE_L)
@ -193,6 +195,19 @@ static int codegen_AND_IMM(codeblock_t *block, uop_t *uop)
return 0;
}
static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop)
{
int dest_reg = HOST_REG_GET(uop->dest_reg_a_real);
int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real);
if (!REG_IS_L(dest_size))
fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real);
host_arm64_call(block, uop->p);
host_arm64_MOV_REG(block, dest_reg, REG_W0, 0);
return 0;
}
static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
{
host_arm64_call(block, uop->p);
@ -217,6 +232,369 @@ static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop)
return 0;
}
static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_arm64_CMP_IMM(block, src_reg, uop->imm_data);
}
else if (REG_IS_W(src_size))
{
host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xffff);
host_arm64_CMP_IMM(block, REG_TEMP, uop->imm_data);
}
else
fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BNE_(block);
return 0;
}
static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_arm64_CMP_IMM(block, src_reg, uop->imm_data);
}
else if (REG_IS_W(src_size))
{
host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xffff);
host_arm64_CMP_IMM(block, REG_TEMP, uop->imm_data);
}
else
fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BEQ_(block);
return 0;
}
static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BCS_(block);
return 0;
}
static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BHI_(block);
return 0;
}
static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BGE_(block);
return 0;
}
static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BGT_(block);
return 0;
}
static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BVC_(block);
return 0;
}
static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BNE_(block);
return 0;
}
static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BCC_(block);
return 0;
}
static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BLS_(block);
return 0;
}
static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BLT_(block);
return 0;
}
static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BLE_(block);
return 0;
}
static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BVS_(block);
return 0;
}
static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm64_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24);
host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BEQ_(block);
return 0;
}
static int codegen_JMP(codeblock_t *block, uop_t *uop)
{
host_arm64_jump(block, (uintptr_t)uop->p);
return 0;
}
static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop)
{
host_arm64_mov_imm(block, REG_ARG0, uop->imm_data);
@ -918,6 +1296,55 @@ static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop)
return 0;
}
static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_arm64_TST_IMM(block, src_reg, 1 << 31);
}
else if (REG_IS_W(src_size))
{
host_arm64_TST_IMM(block, src_reg, 1 << 15);
}
else if (REG_IS_B(src_size))
{
host_arm64_TST_IMM(block, src_reg, 1 << 7);
}
else
fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BEQ_(block);
return 0;
}
static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_arm64_TST_IMM(block, src_reg, 1 << 31);
}
else if (REG_IS_W(src_size))
{
host_arm64_TST_IMM(block, src_reg, 1 << 15);
}
else if (REG_IS_B(src_size))
{
host_arm64_TST_IMM(block, src_reg, 1 << 7);
}
else
fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm64_BNE_(block);
return 0;
}
static int codegen_XOR(codeblock_t *block, uop_t *uop)
{
int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
@ -986,7 +1413,11 @@ static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop)
const uOpFn uop_handlers[UOP_MAX] =
{
[UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT,
[UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC,
[UOP_JMP & UOP_MASK] = codegen_JMP,
[UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG,
[UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM,
@ -1030,7 +1461,26 @@ const uOpFn uop_handlers[UOP_MAX] =
[UOP_SHR & UOP_MASK] = codegen_SHR,
[UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM,
[UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ
[UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ,
[UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST,
[UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST,
[UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST,
[UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST,
[UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST,
[UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST,
[UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST,
[UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST,
[UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST,
[UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST,
[UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST,
[UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST,
[UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST,
[UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST,
[UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST,
[UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST,
};
void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p)
@ -1108,4 +1558,10 @@ void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int hos
fatal("codegen_direct_write_32_stack - not in range\n");
}
void codegen_set_jump_dest(codeblock_t *block, void *p)
{
int offset = (uintptr_t)&block->data[block_pos] - (uintptr_t)p;
*(uint32_t *)p |= OFFSET19(offset);
}
#endif

View file

@ -28,6 +28,18 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val)
#define COND_SHIFT 28
#define COND_EQ (0x0 << COND_SHIFT)
#define COND_NE (0x1 << COND_SHIFT)
#define COND_CS (0x2 << COND_SHIFT)
#define COND_CC (0x3 << COND_SHIFT)
#define COND_MI (0x4 << COND_SHIFT)
#define COND_PL (0x5 << COND_SHIFT)
#define COND_VS (0x6 << COND_SHIFT)
#define COND_VC (0x7 << COND_SHIFT)
#define COND_HI (0x8 << COND_SHIFT)
#define COND_LS (0x9 << COND_SHIFT)
#define COND_GE (0xa << COND_SHIFT)
#define COND_LT (0xb << COND_SHIFT)
#define COND_GT (0xc << COND_SHIFT)
#define COND_LE (0xd << COND_SHIFT)
#define COND_AL (0xe << COND_SHIFT)
#define OPCODE_SHIFT 20
@ -72,6 +84,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val)
#define OPCODE_BFI 0xe7c00010
#define OPCODE_BLX 0xe12fff30
#define OPCODE_BX 0xe12fff10
#define OPCODE_LDRH_IMM 0xe1d000b0
#define OPCODE_LDRH_REG 0xe19000b0
#define OPCODE_STRH_IMM 0xe1c000b0
@ -227,6 +240,19 @@ void host_arm_AND_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int sr
codegen_addlong(block, COND_AL | OPCODE_AND_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift));
}
void host_arm_B(codeblock_t *block, uintptr_t dest_addr)
{
uint32_t offset = (dest_addr - (uintptr_t)&block->data[block_pos]) - 8;
if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000)
{
host_arm_MOV_IMM(block, REG_R3, dest_addr);
host_arm_BX(block, REG_R3);
}
else
codegen_addlong(block, COND_AL | OPCODE_B | B_OFFSET(offset));
}
void host_arm_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width)
{
codegen_addlong(block, OPCODE_BFI | Rd(dst_reg) | Rm(src_reg) | BFI_lsb(lsb) | BFI_msb((lsb + width) - 1));
@ -276,18 +302,90 @@ void host_arm_BLX(codeblock_t *block, int addr_reg)
codegen_addlong(block, OPCODE_BLX | Rm(addr_reg));
}
uint32_t *host_arm_BCC_(codeblock_t *block)
{
codegen_addlong(block, COND_CC | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BCS_(codeblock_t *block)
{
codegen_addlong(block, COND_CS | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BEQ_(codeblock_t *block)
{
codegen_addlong(block, COND_EQ | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BGE_(codeblock_t *block)
{
codegen_addlong(block, COND_GE | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BGT_(codeblock_t *block)
{
codegen_addlong(block, COND_GT | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BHI_(codeblock_t *block)
{
codegen_addlong(block, COND_HI | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BLE_(codeblock_t *block)
{
codegen_addlong(block, COND_LE | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BLS_(codeblock_t *block)
{
codegen_addlong(block, COND_LS | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BLT_(codeblock_t *block)
{
codegen_addlong(block, COND_LT | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BMI_(codeblock_t *block)
{
codegen_addlong(block, COND_MI | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BNE_(codeblock_t *block)
{
codegen_addlong(block, COND_NE | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BPL_(codeblock_t *block)
{
codegen_addlong(block, COND_PL | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BVC_(codeblock_t *block)
{
codegen_addlong(block, COND_VC | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
uint32_t *host_arm_BVS_(codeblock_t *block)
{
codegen_addlong(block, COND_VS | OPCODE_B);
return (uint32_t *)&block->data[block_pos - 4];
}
void host_arm_BEQ(codeblock_t *block, uintptr_t dest_addr)
{
@ -308,6 +406,11 @@ void host_arm_BNE(codeblock_t *block, uintptr_t dest_addr)
codegen_addlong(block, COND_NE | OPCODE_B | B_OFFSET(offset));
}
void host_arm_BX(codeblock_t *block, int addr_reg)
{
codegen_addlong(block, OPCODE_BLX | Rm(addr_reg));
}
void host_arm_CMN_IMM(codeblock_t *block, int src_reg, uint32_t imm)
{
uint32_t arm_imm;

View file

@ -7,6 +7,8 @@ void host_arm_AND_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm
void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift);
void host_arm_AND_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift);
void host_arm_B(codeblock_t *block, uintptr_t dest_addr);
void host_arm_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width);
void host_arm_BIC_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm);
@ -15,15 +17,32 @@ void host_arm_BIC_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int sr
void host_arm_BL(codeblock_t *block, uintptr_t dest_addr);
void host_arm_BLX(codeblock_t *block, int addr_reg);
uint32_t *host_arm_BCC_(codeblock_t *block);
uint32_t *host_arm_BCS_(codeblock_t *block);
uint32_t *host_arm_BEQ_(codeblock_t *block);
uint32_t *host_arm_BGE_(codeblock_t *block);
uint32_t *host_arm_BGT_(codeblock_t *block);
uint32_t *host_arm_BHI_(codeblock_t *block);
uint32_t *host_arm_BLE_(codeblock_t *block);
uint32_t *host_arm_BLS_(codeblock_t *block);
uint32_t *host_arm_BLT_(codeblock_t *block);
uint32_t *host_arm_BMI_(codeblock_t *block);
uint32_t *host_arm_BNE_(codeblock_t *block);
uint32_t *host_arm_BPL_(codeblock_t *block);
uint32_t *host_arm_BVC_(codeblock_t *block);
uint32_t *host_arm_BVS_(codeblock_t *block);
void host_arm_BEQ(codeblock_t *block, uintptr_t dest_addr);
void host_arm_BNE(codeblock_t *block, uintptr_t dest_addr);
void host_arm_BX(codeblock_t *block, int addr_reg);
void host_arm_CMN_IMM(codeblock_t *block, int src_reg, uint32_t imm);
void host_arm_CMN_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift);
void host_arm_CMP_IMM(codeblock_t *block, int src_reg, uint32_t imm);
#define host_arm_CMP_REG(block, src_reg_n, src_reg_m) host_arm_CMP_REG_LSL(block, src_reg_n, src_reg_m, 0)
void host_arm_CMP_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift);
void host_arm_EOR_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm);

View file

@ -268,6 +268,19 @@ static int codegen_AND_IMM(codeblock_t *block, uop_t *uop)
return 0;
}
static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop)
{
int dest_reg = HOST_REG_GET(uop->dest_reg_a_real);
int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real);
if (!REG_IS_L(dest_size))
fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real);
host_arm_call(block, uop->p);
host_arm_MOV_REG(block, dest_reg, REG_R0);
return 0;
}
static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
{
host_arm_call(block, uop->p);
@ -293,6 +306,369 @@ static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop)
return 0;
}
static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_arm_CMP_IMM(block, src_reg, uop->imm_data);
}
else if (REG_IS_W(src_size))
{
host_arm_UXTH(block, REG_TEMP, src_reg, 0);
host_arm_CMP_IMM(block, REG_TEMP, uop->imm_data);
}
else
fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BNE_(block);
return 0;
}
static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_arm_CMP_IMM(block, src_reg, uop->imm_data);
}
else if (REG_IS_W(src_size))
{
host_arm_UXTH(block, REG_TEMP, src_reg, 0);
host_arm_CMP_IMM(block, REG_TEMP, uop->imm_data);
}
else
fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BEQ_(block);
return 0;
}
static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BCS_(block);
return 0;
}
static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BHI_(block);
return 0;
}
static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BGE_(block);
return 0;
}
static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BGT_(block);
return 0;
}
static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BVC_(block);
return 0;
}
static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BNE_(block);
return 0;
}
static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BCC_(block);
return 0;
}
static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BLS_(block);
return 0;
}
static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BLT_(block);
return 0;
}
static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BLE_(block);
return 0;
}
static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BVS_(block);
return 0;
}
static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_arm_CMP_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24);
host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24);
}
else
fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BEQ_(block);
return 0;
}
static int codegen_JMP(codeblock_t *block, uop_t *uop)
{
host_arm_B(block, (uintptr_t)uop->p);
return 0;
}
static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop)
{
host_arm_MOV_IMM(block, REG_ARG0, uop->imm_data);
@ -1000,6 +1376,55 @@ static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop)
return 0;
}
static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_arm_TST_IMM(block, src_reg, 1 << 31);
}
else if (REG_IS_W(src_size))
{
host_arm_TST_IMM(block, src_reg, 1 << 15);
}
else if (REG_IS_B(src_size))
{
host_arm_TST_IMM(block, src_reg, 1 << 7);
}
else
fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BEQ_(block);
return 0;
}
static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_arm_TST_IMM(block, src_reg, 1 << 31);
}
else if (REG_IS_W(src_size))
{
host_arm_TST_IMM(block, src_reg, 1 << 15);
}
else if (REG_IS_B(src_size))
{
host_arm_TST_IMM(block, src_reg, 1 << 7);
}
else
fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_arm_BNE_(block);
return 0;
}
static int codegen_XOR(codeblock_t *block, uop_t *uop)
{
int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
@ -1068,8 +1493,11 @@ static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop)
const uOpFn uop_handlers[UOP_MAX] =
{
[UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT,
[UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC,
[UOP_JMP & UOP_MASK] = codegen_JMP,
[UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG,
[UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM,
@ -1113,7 +1541,26 @@ const uOpFn uop_handlers[UOP_MAX] =
[UOP_SHR & UOP_MASK] = codegen_SHR,
[UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM,
[UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ
[UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ,
[UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST,
[UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST,
[UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST,
[UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST,
[UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST,
[UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST,
[UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST,
[UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST,
[UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST,
[UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST,
[UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST,
[UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST,
[UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST,
[UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST,
[UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST,
[UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST,
};
void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p)
@ -1190,4 +1637,8 @@ void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int hos
fatal("codegen_direct_write_32 - not in range\n");
}
void codegen_set_jump_dest(codeblock_t *block, void *p)
{
*(uint32_t *)p |= ((((uintptr_t)&block->data[block_pos] - (uintptr_t)p) - 8) & 0x3fffffc) >> 2;
}
#endif

View file

@ -117,6 +117,23 @@ static inline void call(codeblock_t *block, uintptr_t func)
}
}
static inline void jmp(codeblock_t *block, uintptr_t func)
{
uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5];
if (diff >= -0x80000000 && diff < 0x7fffffff)
{
codegen_addbyte(block, 0xe9); /*JMP*/
codegen_addlong(block, (uint32_t)diff);
}
else
{
codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, func*/
codegen_addquad(block, func);
codegen_addbyte3(block, 0x41, 0xff, 0xe1); /*JMP R9*/
}
}
void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data)
{
if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8))
@ -268,6 +285,21 @@ void host_x86_CALL(codeblock_t *block, void *p)
call(block, (uintptr_t)p);
}
void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data)
{
if (is_imm8(imm_data))
codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/
else if (dst_reg == REG_EAX)
{
codegen_addbyte2(block, 0x66, 0x3d); /*CMP AX, imm_data*/
codegen_addword(block, imm_data);
}
else
{
codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/
codegen_addword(block, imm_data);
}
}
void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data)
{
if (is_imm8(imm_data))
@ -291,6 +323,24 @@ void host_x86_CMP64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data)
fatal("CMP64_REG_IMM not 8-bit imm\n");
}
void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b)
{
codegen_addbyte2(block, 0x38, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/
}
void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b)
{
codegen_addbyte3(block, 0x66, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/
}
void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b)
{
codegen_addbyte2(block, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/
}
void host_x86_JMP(codeblock_t *block, void *p)
{
jmp(block, (uintptr_t)p);
}
void host_x86_JNZ(codeblock_t *block, void *p)
{
codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/
@ -313,6 +363,91 @@ uint8_t *host_x86_JZ_short(codeblock_t *block)
return &block->data[block_pos-1];
}
uint32_t *host_x86_JNB_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x83); /*JNB*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNBE_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x87); /*JNBE*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNL_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x8d); /*JNL*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNLE_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x8f); /*JNLE*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNO_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x81); /*JNO*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNS_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x89); /*JNS*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNZ_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JB_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x82); /*JB*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JBE_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x86); /*JBE*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JL_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x8c); /*JL*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JLE_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x8e); /*JLE*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JO_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x80); /*JO*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JS_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x88); /*JS*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JZ_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset)
{
if (offset)
@ -1007,6 +1142,14 @@ void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int
#define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3))
void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg)
{
codegen_addbyte2(block, 0x84, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/
}
void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg)
{
codegen_addbyte3(block, 0x66, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/
}
void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg)
{
if ((dst_reg & 8) || (src_reg & 8))

View file

@ -17,15 +17,37 @@ void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int
void host_x86_CALL(codeblock_t *block, void *p);
void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data);
void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data);
void host_x86_CMP64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data);
void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b);
void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b);
void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b);
void host_x86_JMP(codeblock_t *block, void *p);
void host_x86_JNZ(codeblock_t *block, void *p);
void host_x86_JZ(codeblock_t *block, void *p);
uint8_t *host_x86_JNZ_short(codeblock_t *block);
uint8_t *host_x86_JZ_short(codeblock_t *block);
uint32_t *host_x86_JNB_long(codeblock_t *block);
uint32_t *host_x86_JNBE_long(codeblock_t *block);
uint32_t *host_x86_JNL_long(codeblock_t *block);
uint32_t *host_x86_JNLE_long(codeblock_t *block);
uint32_t *host_x86_JNO_long(codeblock_t *block);
uint32_t *host_x86_JNS_long(codeblock_t *block);
uint32_t *host_x86_JNZ_long(codeblock_t *block);
uint32_t *host_x86_JB_long(codeblock_t *block);
uint32_t *host_x86_JBE_long(codeblock_t *block);
uint32_t *host_x86_JL_long(codeblock_t *block);
uint32_t *host_x86_JLE_long(codeblock_t *block);
uint32_t *host_x86_JO_long(codeblock_t *block);
uint32_t *host_x86_JS_long(codeblock_t *block);
uint32_t *host_x86_JZ_long(codeblock_t *block);
void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset);
void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b);
void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift);
@ -122,6 +144,8 @@ void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int s
void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b);
void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b);
void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg);
void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg);
void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg);
void host_x86_TEST32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data);

View file

@ -149,6 +149,19 @@ static int codegen_AND_IMM(codeblock_t *block, uop_t *uop)
return 0;
}
static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop)
{
int dest_reg = HOST_REG_GET(uop->dest_reg_a_real);
int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real);
if (!REG_IS_L(dest_size))
fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real);
host_x86_CALL(block, uop->p);
host_x86_MOV32_REG_REG(block, dest_reg, REG_EAX);
return 0;
}
static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
{
host_x86_CALL(block, uop->p);
@ -174,6 +187,343 @@ static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop)
return 0;
}
static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data);
}
else if (REG_IS_W(src_size))
{
host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data);
}
else
fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNZ_long(block);
return 0;
}
static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data);
}
else if (REG_IS_W(src_size))
{
host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data);
}
else
fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JZ_long(block);
return 0;
}
static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNB_long(block);
return 0;
}
static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNBE_long(block);
return 0;
}
static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNL_long(block);
return 0;
}
static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNLE_long(block);
return 0;
}
static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNO_long(block);
return 0;
}
static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNZ_long(block);
return 0;
}
static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JB_long(block);
return 0;
}
static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JBE_long(block);
return 0;
}
static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JL_long(block);
return 0;
}
static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JLE_long(block);
return 0;
}
static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JO_long(block);
return 0;
}
static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JZ_long(block);
return 0;
}
static int codegen_JMP(codeblock_t *block, uop_t *uop)
{
host_x86_JMP(block, uop->p);
return 0;
}
static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop)
{
#if WIN64
@ -759,6 +1109,55 @@ static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop)
return 0;
}
static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_x86_TEST32_REG(block, src_reg, src_reg);
}
else if (REG_IS_W(src_size))
{
host_x86_TEST16_REG(block, src_reg, src_reg);
}
else if (REG_IS_B(src_size))
{
host_x86_TEST8_REG(block, src_reg, src_reg);
}
else
fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNS_long(block);
return 0;
}
static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_x86_TEST32_REG(block, src_reg, src_reg);
}
else if (REG_IS_W(src_size))
{
host_x86_TEST16_REG(block, src_reg, src_reg);
}
else if (REG_IS_B(src_size))
{
host_x86_TEST8_REG(block, src_reg, src_reg);
}
else
fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JS_long(block);
return 0;
}
static int codegen_XOR(codeblock_t *block, uop_t *uop)
{
int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
@ -806,8 +1205,11 @@ static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop)
const uOpFn uop_handlers[UOP_MAX] =
{
[UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT,
[UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC,
[UOP_JMP & UOP_MASK] = codegen_JMP,
[UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG,
[UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM,
@ -851,7 +1253,26 @@ const uOpFn uop_handlers[UOP_MAX] =
[UOP_SHR & UOP_MASK] = codegen_SHR,
[UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM,
[UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ
[UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ,
[UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST,
[UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST,
[UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST,
[UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST,
[UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST,
[UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST,
[UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST,
[UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST,
[UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST,
[UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST,
[UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST,
[UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST,
[UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST,
[UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST,
[UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST,
[UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST,
};
void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p)
@ -895,4 +1316,9 @@ void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int hos
host_x86_MOV32_BASE_OFFSET_REG(block, REG_RSP, stack_offset, host_reg);
}
void codegen_set_jump_dest(codeblock_t *block, void *p)
{
*(uint32_t *)p = (uintptr_t)&block->data[block_pos] - ((uintptr_t)p + 4);
}
#endif

View file

@ -260,6 +260,21 @@ void host_x86_CALL(codeblock_t *block, void *p)
codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]);
}
void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data)
{
if (is_imm8(imm_data))
codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/
else if (dst_reg == REG_EAX)
{
codegen_addbyte2(block, 0x66, 0x3d); /*CMP AX, imm_data*/
codegen_addword(block, imm_data);
}
else
{
codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/
codegen_addword(block, imm_data);
}
}
void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data)
{
if (is_imm8(imm_data))
@ -276,6 +291,25 @@ void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data)
}
}
void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b)
{
codegen_addbyte2(block, 0x38, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/
}
void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b)
{
codegen_addbyte3(block, 0x66, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/
}
void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b)
{
codegen_addbyte2(block, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/
}
void host_x86_JMP(codeblock_t *block, void *p)
{
codegen_addbyte(block, 0xe9); /*JMP*/
codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]);
}
void host_x86_JNZ(codeblock_t *block, void *p)
{
codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/
@ -298,6 +332,91 @@ uint8_t *host_x86_JZ_short(codeblock_t *block)
return &block->data[block_pos-1];
}
uint32_t *host_x86_JNB_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x83); /*JNB*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNBE_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x87); /*JNBE*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNL_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x8d); /*JNL*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNLE_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x8f); /*JNLE*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNO_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x81); /*JNO*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNS_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x89); /*JNS*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JNZ_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JB_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x82); /*JB*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JBE_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x86); /*JBE*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JL_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x8c); /*JL*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JLE_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x8e); /*JLE*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JO_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x80); /*JO*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JS_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x88); /*JS*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
uint32_t *host_x86_JZ_long(codeblock_t *block)
{
codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/
codegen_addlong(block, 0);
return (uint32_t *)&block->data[block_pos-4];
}
void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset)
{
if (offset)
@ -856,6 +975,14 @@ void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int
codegen_addbyte2(block, 0x29, 0xc0 | dst_reg | (src_reg_b << 3)); /*SUB dst_reg, src_reg_b*/
}
void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg)
{
codegen_addbyte2(block, 0x84, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/
}
void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg)
{
codegen_addbyte3(block, 0x66, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/
}
void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg)
{
codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/

View file

@ -18,14 +18,36 @@ void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int
void host_x86_CALL(codeblock_t *block, void *p);
void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data);
void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data);
void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b);
void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b);
void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b);
void host_x86_JMP(codeblock_t *block, void *p);
void host_x86_JNZ(codeblock_t *block, void *p);
void host_x86_JZ(codeblock_t *block, void *p);
uint8_t *host_x86_JNZ_short(codeblock_t *block);
uint8_t *host_x86_JZ_short(codeblock_t *block);
uint32_t *host_x86_JNB_long(codeblock_t *block);
uint32_t *host_x86_JNBE_long(codeblock_t *block);
uint32_t *host_x86_JNL_long(codeblock_t *block);
uint32_t *host_x86_JNLE_long(codeblock_t *block);
uint32_t *host_x86_JNO_long(codeblock_t *block);
uint32_t *host_x86_JNS_long(codeblock_t *block);
uint32_t *host_x86_JNZ_long(codeblock_t *block);
uint32_t *host_x86_JB_long(codeblock_t *block);
uint32_t *host_x86_JBE_long(codeblock_t *block);
uint32_t *host_x86_JL_long(codeblock_t *block);
uint32_t *host_x86_JLE_long(codeblock_t *block);
uint32_t *host_x86_JO_long(codeblock_t *block);
uint32_t *host_x86_JS_long(codeblock_t *block);
uint32_t *host_x86_JZ_long(codeblock_t *block);
void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg_a, uint32_t offset);
void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b);
void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift);
@ -121,7 +143,10 @@ void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int s
void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b);
void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b);
void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg);
void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg);
void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg);
void host_x86_TEST32_REG_IMM(codeblock_t *block, int src_host_reg, uint32_t imm_data);
void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b);

View file

@ -159,6 +159,19 @@ static int codegen_AND_IMM(codeblock_t *block, uop_t *uop)
return 0;
}
static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop)
{
int dest_reg = HOST_REG_GET(uop->dest_reg_a_real);
int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real);
if (!REG_IS_L(dest_size))
fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real);
host_x86_CALL(block, uop->p);
host_x86_MOV32_REG_REG(block, dest_reg, REG_EAX);
return 0;
}
static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
{
host_x86_CALL(block, uop->p);
@ -181,10 +194,347 @@ static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop)
else
fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real);
host_x86_JZ(block, uop->p);
return 0;
}
static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data);
}
else if (REG_IS_W(src_size))
{
host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data);
}
else
fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNZ_long(block);
return 0;
}
static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data);
}
else if (REG_IS_W(src_size))
{
host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data);
}
else
fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JZ_long(block);
return 0;
}
static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNB_long(block);
return 0;
}
static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNBE_long(block);
return 0;
}
static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNL_long(block);
return 0;
}
static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNLE_long(block);
return 0;
}
static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNO_long(block);
return 0;
}
static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNZ_long(block);
return 0;
}
static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JB_long(block);
return 0;
}
static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JBE_long(block);
return 0;
}
static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JL_long(block);
return 0;
}
static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JLE_long(block);
return 0;
}
static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JO_long(block);
return 0;
}
static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real);
if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b))
{
host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b))
{
host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b);
}
else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b))
{
host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b);
}
else
fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JZ_long(block);
return 0;
}
static int codegen_JMP(codeblock_t *block, uop_t *uop)
{
host_x86_JMP(block, uop->p);
return 0;
}
static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop)
{
host_x86_MOV32_STACK_IMM(block, STACK_ARG0, uop->imm_data);
@ -752,6 +1102,55 @@ static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop)
return 0;
}
static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_x86_TEST32_REG(block, src_reg, src_reg);
}
else if (REG_IS_W(src_size))
{
host_x86_TEST16_REG(block, src_reg, src_reg);
}
else if (REG_IS_B(src_size))
{
host_x86_TEST8_REG(block, src_reg, src_reg);
}
else
fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JNS_long(block);
return 0;
}
static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop)
{
int src_reg = HOST_REG_GET(uop->src_reg_a_real);
int src_size = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_L(src_size))
{
host_x86_TEST32_REG(block, src_reg, src_reg);
}
else if (REG_IS_W(src_size))
{
host_x86_TEST16_REG(block, src_reg, src_reg);
}
else if (REG_IS_B(src_size))
{
host_x86_TEST8_REG(block, src_reg, src_reg);
}
else
fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real);
uop->p = host_x86_JS_long(block);
return 0;
}
static int codegen_XOR(codeblock_t *block, uop_t *uop)
{
int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real);
@ -799,8 +1198,11 @@ static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop)
const uOpFn uop_handlers[UOP_MAX] =
{
[UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT,
[UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC,
[UOP_JMP & UOP_MASK] = codegen_JMP,
[UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG,
[UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM,
@ -844,7 +1246,26 @@ const uOpFn uop_handlers[UOP_MAX] =
[UOP_SHR & UOP_MASK] = codegen_SHR,
[UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM,
[UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ
[UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ,
[UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST,
[UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST,
[UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST,
[UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST,
[UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST,
[UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST,
[UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST,
[UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST,
[UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST,
[UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST,
[UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST,
[UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST,
[UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST,
[UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST,
[UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST,
[UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST,
};
void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p)
@ -888,4 +1309,9 @@ void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int hos
host_x86_MOV32_BASE_OFFSET_REG(block, REG_ESP, stack_offset, host_reg);
}
void codegen_set_jump_dest(codeblock_t *block, void *p)
{
*(uint32_t *)p = (uintptr_t)&block->data[block_pos] - ((uintptr_t)p + 4);
}
#endif

View file

@ -17,6 +17,7 @@ ir_data_t *codegen_ir_init()
void codegen_ir_compile(ir_data_t *ir, codeblock_t *block)
{
int jump_target_at_end = -1;
int c;
codegen_backend_prologue(block);
@ -26,12 +27,23 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block)
uop_t *uop = &ir->uops[c];
// pclog("uOP %i : %08x\n", c, uop->type);
if (uop->type & UOP_TYPE_BARRIER)
codegen_reg_flush_invalidate(ir, block);
else if (uop->type & UOP_TYPE_ORDER_BARRIER)
codegen_reg_flush(ir, block);
if (uop->type & UOP_TYPE_JUMP_DEST)
{
uop_t *uop_dest = uop;
while (uop_dest->jump_list_next != -1)
{
uop_dest = &ir->uops[uop_dest->jump_list_next];
codegen_set_jump_dest(block, uop_dest->p);
}
}
if (uop->type & UOP_TYPE_PARAMS_REGS)
{
codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b, uop->src_reg_c);
@ -56,10 +68,51 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block)
if (!uop_handlers[uop->type & UOP_MASK])
fatal("!uop_handlers[uop->type & UOP_MASK]\n");
uop_handlers[uop->type & UOP_MASK](block, uop);
if (uop->type & UOP_TYPE_JUMP)
{
if (uop->jump_dest_uop == ir->wr_pos)
{
if (jump_target_at_end == -1)
jump_target_at_end = c;
else
{
uop_t *uop_dest = &ir->uops[jump_target_at_end];
while (uop_dest->jump_list_next != -1)
uop_dest = &ir->uops[uop_dest->jump_list_next];
uop_dest->jump_list_next = c;
}
}
else
{
uop_t *uop_dest = &ir->uops[uop->jump_dest_uop];
while (uop_dest->jump_list_next != -1)
uop_dest = &ir->uops[uop_dest->jump_list_next];
uop_dest->jump_list_next = c;
ir->uops[uop->jump_dest_uop].type |= UOP_TYPE_JUMP_DEST;
}
}
}
codegen_reg_flush_invalidate(ir, block);
if (jump_target_at_end != -1)
{
uop_t *uop_dest = &ir->uops[jump_target_at_end];
while (1)
{
codegen_set_jump_dest(block, uop_dest->p);
if (uop_dest->jump_list_next == -1)
break;
uop_dest = &ir->uops[uop_dest->jump_list_next];
}
}
codegen_backend_epilogue(block);
// if (has_ea)

View file

@ -24,6 +24,13 @@
/*uOP uses immediate data*/
#define UOP_TYPE_PARAMS_IMM (1 << 30)
/*uOP is a jump, with the destination uOP in uop->jump_dest_uop. The compiler must
set jump_dest in the destination uOP to the address of the branch offset to be
written when known.*/
#define UOP_TYPE_JUMP (1 << 26)
/*uOP is the destination of a jump, and must set the destination offset of the jump
at compile time.*/
#define UOP_TYPE_JUMP_DEST (1 << 25)
#define UOP_LOAD_FUNC_ARG_0 (UOP_TYPE_PARAMS_REGS | 0x00)
@ -41,6 +48,10 @@
#define UOP_STORE_P_IMM_8 (UOP_TYPE_PARAMS_IMM | 0x13)
/*UOP_LOAD_SEG - load segment in src_reg_a to segment p via loadseg(), check return value and exit block if non-zero*/
#define UOP_LOAD_SEG (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x14 | UOP_TYPE_BARRIER)
/*UOP_JMP - jump to ptr*/
#define UOP_JMP (UOP_TYPE_PARAMS_POINTER | 0x15 | UOP_TYPE_ORDER_BARRIER)
/*UOP_CALL_FUNC - call instruction handler at p, dest_reg = return value*/
#define UOP_CALL_FUNC_RESULT (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x16 | UOP_TYPE_BARRIER)
/*UOP_MOV_PTR - dest_reg = p*/
#define UOP_MOV_PTR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x20)
/*UOP_MOV_IMM - dest_reg = imm_data*/
@ -86,7 +97,7 @@
#define UOP_MEM_STORE_IMM_16 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x45 | UOP_TYPE_ORDER_BARRIER)
/*UOP_MEM_STORE_IMM_32 - long src_reg_a:[src_reg_b] = imm_data*/
#define UOP_MEM_STORE_IMM_32 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x46 | UOP_TYPE_ORDER_BARRIER)
/*UOP_CMP_JZ - if (src_reg_a == imm_data) then jump to ptr*/
/*UOP_CMP_IMM_JZ - if (src_reg_a == imm_data) then jump to ptr*/
#define UOP_CMP_IMM_JZ (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x48 | UOP_TYPE_ORDER_BARRIER)
/*UOP_SAR - dest_reg = src_reg_a >> src_reg_b*/
@ -102,7 +113,43 @@
/*UOP_SHR_IMM - dest_reg = src_reg_a >> immediate*/
#define UOP_SHR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x55)
#define UOP_MAX 0x56
/*UOP_CMP_IMM_JZ_DEST - if (src_reg_a == imm_data) then jump to ptr*/
#define UOP_CMP_IMM_JZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x60 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_IMM_JNZ_DEST - if (src_reg_a != imm_data) then jump to ptr*/
#define UOP_CMP_IMM_JNZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x61 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JB_DEST - if (src_reg_a < src_reg_b) then jump to ptr*/
#define UOP_CMP_JB_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x62 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JNB_DEST - if (src_reg_a >= src_reg_b) then jump to ptr*/
#define UOP_CMP_JNB_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x63 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JO_DEST - if (src_reg_a < src_reg_b) then jump to ptr*/
#define UOP_CMP_JO_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x64 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JNO_DEST - if (src_reg_a >= src_reg_b) then jump to ptr*/
#define UOP_CMP_JNO_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x65 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JZ_DEST - if (src_reg_a == src_reg_b) then jump to ptr*/
#define UOP_CMP_JZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x66 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JNZ_DEST - if (src_reg_a != src_reg_b) then jump to ptr*/
#define UOP_CMP_JNZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x67 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JL_DEST - if (signed)(src_reg_a < src_reg_b) then jump to ptr*/
#define UOP_CMP_JL_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x68 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JNL_DEST - if (signed)(src_reg_a >= src_reg_b) then jump to ptr*/
#define UOP_CMP_JNL_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x69 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JBE_DEST - if (src_reg_a <= src_reg_b) then jump to ptr*/
#define UOP_CMP_JBE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6a | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JNBE_DEST - if (src_reg_a > src_reg_b) then jump to ptr*/
#define UOP_CMP_JNBE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6b | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JLE_DEST - if (signed)(src_reg_a <= src_reg_b) then jump to ptr*/
#define UOP_CMP_JLE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6c | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_CMP_JNLE_DEST - if (signed)(src_reg_a > src_reg_b) then jump to ptr*/
#define UOP_CMP_JNLE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6d | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_TEST_JNS_DEST - if (src_reg_a positive) then jump to ptr*/
#define UOP_TEST_JNS_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x70 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
/*UOP_TEST_JS_DEST - if (src_reg_a positive) then jump to ptr*/
#define UOP_TEST_JS_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x71 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
#define UOP_MAX 0x72
#define UOP_MASK 0xffff
@ -117,6 +164,9 @@ typedef struct uop_t
void *p;
ir_host_reg_t dest_reg_a_real;
ir_host_reg_t src_reg_a_real, src_reg_b_real, src_reg_c_real;
int jump_dest_uop;
int jump_list_next;
void *jump_dest;
} uop_t;
#define UOP_NR_MAX 4096
@ -141,15 +191,45 @@ static inline uop_t *uop_alloc(ir_data_t *ir)
uop->src_reg_b = invalid_ir_reg;
uop->src_reg_c = invalid_ir_reg;
uop->jump_list_next = -1;
return uop;
}
static inline void uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int arg, int src_reg_a)
static inline void uop_set_jump_dest(ir_data_t *ir, int jump_uop)
{
uop_t *uop = &ir->uops[jump_uop];
uop->jump_dest_uop = ir->wr_pos;
}
static inline int uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int src_reg_a)
{
uop_t *uop = uop_alloc(ir);
uop->type = uop_type;
uop->src_reg_a = codegen_reg_read(src_reg_a);
return ir->wr_pos-1;
}
static inline void uop_gen_reg_src1_arg(uint32_t uop_type, ir_data_t *ir, int arg, int src_reg_a)
{
uop_t *uop = uop_alloc(ir);
uop->type = uop_type;
uop->src_reg_a = codegen_reg_read(src_reg_a);
}
static inline int uop_gen_reg_src1_imm(uint32_t uop_type, ir_data_t *ir, int src_reg, uint32_t imm)
{
uop_t *uop = uop_alloc(ir);
uop->type = uop_type;
uop->src_reg_a = codegen_reg_read(src_reg);
uop->imm_data = imm;
return ir->wr_pos-1;
}
static inline void uop_gen_reg_dst_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, uint32_t imm)
@ -220,6 +300,17 @@ static inline void uop_gen_reg_dst_src_imm(uint32_t uop_type, ir_data_t *ir, int
uop->imm_data = imm;
}
static inline int uop_gen_reg_src2(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b)
{
uop_t *uop = uop_alloc(ir);
uop->type = uop_type;
uop->src_reg_a = codegen_reg_read(src_reg_a);
uop->src_reg_b = codegen_reg_read(src_reg_b);
return ir->wr_pos-1;
}
static inline void uop_gen_reg_src2_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, uint32_t imm)
{
uop_t *uop = uop_alloc(ir);
@ -284,7 +375,7 @@ static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir,
uop->imm_data = imm;
}
#define uop_LOAD_FUNC_ARG_REG(ir, arg, reg) uop_gen_reg_src1(UOP_LOAD_FUNC_ARG_0 + arg, ir, reg)
#define uop_LOAD_FUNC_ARG_REG(ir, arg, reg) uop_gen_reg_src1_arg(UOP_LOAD_FUNC_ARG_0 + arg, ir, reg)
#define uop_LOAD_FUNC_ARG_IMM(ir, arg, imm) uop_gen_imm(UOP_LOAD_FUNC_ARG_0_IMM + arg, ir, imm)
@ -307,11 +398,30 @@ static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir,
#define uop_SHR(ir, dst_reg, src_reg, shift_reg) uop_gen_reg_dst_src2(UOP_SHR, ir, dst_reg, src_reg, shift_reg)
#define uop_SHR_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_SHR_IMM, ir, dst_reg, src_reg, imm)
#define uop_CALL_FUNC(ir, p) uop_gen_pointer(UOP_CALL_FUNC, ir, p)
#define uop_CALL_INSTRUCTION_FUNC(ir, p) uop_gen_pointer(UOP_CALL_INSTRUCTION_FUNC, ir, p)
#define uop_CALL_FUNC(ir, p) uop_gen_pointer(UOP_CALL_FUNC, ir, p)
#define uop_CALL_FUNC_RESULT(ir, dst_reg, p) uop_gen_reg_dst_pointer(UOP_CALL_FUNC_RESULT, ir, dst_reg, p)
#define uop_CALL_INSTRUCTION_FUNC(ir, p) uop_gen_pointer(UOP_CALL_INSTRUCTION_FUNC, ir, p)
#define uop_CMP_IMM_JZ(ir, src_reg, imm, p) uop_gen_reg_src_pointer_imm(UOP_CMP_IMM_JZ, ir, src_reg, p, imm)
#define uop_CMP_IMM_JNZ_DEST(ir, src_reg, imm) uop_gen_reg_src1_imm(UOP_CMP_IMM_JNZ_DEST, ir, src_reg, imm)
#define uop_CMP_IMM_JZ_DEST(ir, src_reg, imm) uop_gen_reg_src1_imm(UOP_CMP_IMM_JZ_DEST, ir, src_reg, imm)
#define uop_CMP_JNB_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNB_DEST, ir, src_reg_a, src_reg_b)
#define uop_CMP_JNBE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNBE_DEST, ir, src_reg_a, src_reg_b)
#define uop_CMP_JNL_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNL_DEST, ir, src_reg_a, src_reg_b)
#define uop_CMP_JNLE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNLE_DEST, ir, src_reg_a, src_reg_b)
#define uop_CMP_JNO_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNO_DEST, ir, src_reg_a, src_reg_b)
#define uop_CMP_JNZ_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNZ_DEST, ir, src_reg_a, src_reg_b)
#define uop_CMP_JB_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JB_DEST, ir, src_reg_a, src_reg_b)
#define uop_CMP_JBE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JBE_DEST, ir, src_reg_a, src_reg_b)
#define uop_CMP_JL_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JL_DEST, ir, src_reg_a, src_reg_b)
#define uop_CMP_JLE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JLE_DEST, ir, src_reg_a, src_reg_b)
#define uop_CMP_JO_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JO_DEST, ir, src_reg_a, src_reg_b)
#define uop_CMP_JZ_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JZ_DEST, ir, src_reg_a, src_reg_b)
#define uop_JMP(ir, p) uop_gen_pointer(UOP_JMP, ir, p)
#define uop_LOAD_SEG(ir, p, src_reg) uop_gen_reg_src_pointer(UOP_LOAD_SEG, ir, src_reg, p)
#define uop_MEM_LOAD_ABS(ir, dst_reg, seg_reg, imm) uop_gen_reg_dst_src_imm(UOP_MEM_LOAD_ABS, ir, dst_reg, seg_reg, imm)
@ -330,6 +440,9 @@ static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir,
#define uop_STORE_PTR_IMM(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM, ir, p, imm)
#define uop_STORE_PTR_IMM_8(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM_8, ir, p, imm)
#define uop_TEST_JNS_DEST(ir, src_reg) uop_gen_reg_src1(UOP_TEST_JNS_DEST, ir, src_reg)
#define uop_TEST_JS_DEST(ir, src_reg) uop_gen_reg_src1(UOP_TEST_JS_DEST, ir, src_reg)
void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p);
void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p);
@ -343,4 +456,6 @@ void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_of
void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int host_reg);
void codegen_set_jump_dest(codeblock_t *block, void *p);
#endif

View file

@ -3,6 +3,7 @@
#include "codegen_ir.h"
#include "codegen_ops.h"
#include "codegen_ops_arith.h"
#include "codegen_ops_branch.h"
#include "codegen_ops_jump.h"
#include "codegen_ops_logic.h"
#include "codegen_ops_misc.h"
@ -22,7 +23,7 @@ RecompOpFn recomp_opcodes[512] =
/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*50*/ ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16,
/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_16, NULL, ropPUSH_imm_16_8,NULL, NULL, NULL, NULL, NULL,
/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*70*/ ropJO_8, ropJNO_8, ropJB_8, ropJNB_8, ropJE_8, ropJNE_8, ropJBE_8, ropJNBE_8, ropJS_8, ropJNS_8, ropJP_8, ropJNP_8, ropJL_8, ropJNL_8, ropJLE_8, ropJNLE_8,
/*80*/ rop80, rop81_w, rop80, rop83_w, ropTEST_b_rm, ropTEST_w_rm, ropXCHG_8, ropXCHG_16, ropMOV_b_r, ropMOV_w_r, ropMOV_r_b, ropMOV_r_w, ropMOV_w_seg, ropLEA_16, ropMOV_seg_w, ropPOP_W,
/*90*/ ropNOP, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@ -31,7 +32,7 @@ RecompOpFn recomp_opcodes[512] =
/*c0*/ ropC0, ropC1_w, ropRET_imm_16, ropRET_16, NULL, NULL, ropMOV_b_imm, ropMOV_w_imm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*d0*/ ropD0, ropD1_w, ropD2, ropD3_w, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropCALL_r16, ropJMP_r16, NULL, ropJMP_r8, NULL, NULL, NULL, NULL,
/*e0*/ ropLOOPNE, ropLOOPE, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r16, ropJMP_r16, NULL, ropJMP_r8, NULL, NULL, NULL, NULL,
/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_16, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFF_16,
/*32-bit data*/
@ -44,7 +45,7 @@ RecompOpFn recomp_opcodes[512] =
/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*50*/ ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32,
/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_32, NULL, ropPUSH_imm_32_8,NULL, NULL, NULL, NULL, NULL,
/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*70*/ ropJO_8, ropJNO_8, ropJB_8, ropJNB_8, ropJE_8, ropJNE_8, ropJBE_8, ropJNBE_8, ropJS_8, ropJNS_8, ropJP_8, ropJNP_8, ropJL_8, ropJNL_8, ropJLE_8, ropJNLE_8,
/*80*/ rop80, rop81_l, rop80, rop83_l, ropTEST_b_rm, ropTEST_l_rm, ropXCHG_8, ropXCHG_32, ropMOV_b_r, ropMOV_l_r, ropMOV_r_b, ropMOV_r_l, ropMOV_l_seg, ropLEA_32, ropMOV_seg_w, ropPOP_L,
/*90*/ ropNOP, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@ -53,7 +54,7 @@ RecompOpFn recomp_opcodes[512] =
/*c0*/ ropC0, ropC1_l, ropRET_imm_32, ropRET_32, NULL, NULL, ropMOV_b_imm, ropMOV_l_imm, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*d0*/ ropD0, ropD1_l, ropD2, ropD3_l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropCALL_r32, ropJMP_r32, NULL, ropJMP_r8, NULL, NULL, NULL, NULL,
/*e0*/ ropLOOPNE, ropLOOPE, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r32, ropJMP_r32, NULL, ropJMP_r8, NULL, NULL, NULL, NULL,
/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_32, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFF_32
};
@ -72,7 +73,7 @@ RecompOpFn recomp_opcodes_0f[512] =
/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*80*/ ropJO_16, ropJNO_16, ropJB_16, ropJNB_16, ropJE_16, ropJNE_16, ropJBE_16, ropJNBE_16, ropJS_16, ropJNS_16, ropJP_16, ropJNP_16, ropJL_16, ropJNL_16, ropJLE_16, ropJNLE_16,
/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*a0*/ ropPUSH_FS_16, ropPOP_FS_16, NULL, NULL, ropSHLD_16_imm, NULL, NULL, NULL, ropPUSH_GS_16, ropPOP_GS_16, NULL, NULL, ropSHRD_16_imm, NULL, NULL, NULL,
/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropMOVZX_16_8, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@ -94,7 +95,7 @@ RecompOpFn recomp_opcodes_0f[512] =
/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*80*/ ropJO_32, ropJNO_32, ropJB_32, ropJNB_32, ropJE_32, ropJNE_32, ropJBE_32, ropJNBE_32, ropJS_32, ropJNS_32, ropJP_32, ropJNP_32, ropJL_32, ropJNL_32, ropJLE_32, ropJNLE_32,
/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*a0*/ ropPUSH_FS_32, ropPOP_FS_32, NULL, NULL, ropSHLD_32_imm, NULL, NULL, NULL, ropPUSH_GS_32, ropPOP_GS_32, NULL, NULL, ropSHRD_32_imm, NULL, NULL, NULL,
/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropMOVZX_32_8, ropMOVZX_32_16, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

662
src/codegen_ops_branch.c Normal file
View file

@ -0,0 +1,662 @@
#include "ibm.h"
#include "x86.h"
#include "386_common.h"
#include "x86_flags.h"
#include "codegen.h"
#include "codegen_backend.h"
#include "codegen_ir.h"
#include "codegen_ops.h"
#include "codegen_ops_helpers.h"
#include "codegen_ops_mov.h"
static int NF_SET_01()
{
return NF_SET() ? 1 : 0;
}
static int VF_SET_01()
{
return VF_SET() ? 1 : 0;
}
static void ropJO_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
{
case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32:
/*Overflow is always zero*/
return;
case FLAGS_SUB8: case FLAGS_DEC8:
jump_uop = uop_CMP_JNO_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
break;
case FLAGS_SUB16: case FLAGS_DEC16:
jump_uop = uop_CMP_JNO_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
break;
case FLAGS_SUB32: case FLAGS_DEC32:
jump_uop = uop_CMP_JNO_DEST(ir, IREG_flags_op1, IREG_flags_op2);
break;
case FLAGS_UNKNOWN:
default:
uop_CALL_FUNC_RESULT(ir, IREG_temp0, VF_SET);
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
break;
}
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJNO_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
{
case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32:
/*Overflow is always zero*/
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
return;
case FLAGS_SUB8: case FLAGS_DEC8:
jump_uop = uop_CMP_JO_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B);
break;
case FLAGS_SUB16: case FLAGS_DEC16:
jump_uop = uop_CMP_JO_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W);
break;
case FLAGS_SUB32: case FLAGS_DEC32:
jump_uop = uop_CMP_JO_DEST(ir, IREG_flags_op1, IREG_flags_op2);
break;
case FLAGS_UNKNOWN:
default:
uop_CALL_FUNC_RESULT(ir, IREG_temp0, VF_SET);
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
break;
}
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJB_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
{
case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32:
/*Carry is always zero*/
return;
case FLAGS_SUB8:
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);
break;
case FLAGS_SUB32:
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);
break;
}
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJNB_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
{
case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32:
/*Carry is always zero*/
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
return;
case FLAGS_SUB8:
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);
break;
case FLAGS_SUB32:
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);
break;
}
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJE_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
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, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
void ropJNE_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
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, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJBE_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop, jump_uop2 = -1;
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);
break;
case FLAGS_SUB8:
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);
break;
case FLAGS_SUB32:
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);
break;
}
if (jump_uop2 != -1)
uop_set_jump_dest(ir, jump_uop2);
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJNBE_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop, jump_uop2 = -1;
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);
break;
case FLAGS_SUB8:
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);
break;
case FLAGS_SUB32:
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);
break;
}
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
if (jump_uop2 != -1)
uop_set_jump_dest(ir, jump_uop2);
}
static void ropJS_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
{
case FLAGS_ZN8:
case FLAGS_ADD8:
case FLAGS_SUB8:
case FLAGS_SHL8:
case FLAGS_SHR8:
case FLAGS_SAR8:
case FLAGS_INC8:
case FLAGS_DEC8:
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B);
break;
case FLAGS_ZN16:
case FLAGS_ADD16:
case FLAGS_SUB16:
case FLAGS_SHL16:
case FLAGS_SHR16:
case FLAGS_SAR16:
case FLAGS_INC16:
case FLAGS_DEC16:
jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W);
break;
case FLAGS_ZN32:
case FLAGS_ADD32:
case FLAGS_SUB32:
case FLAGS_SHL32:
case FLAGS_SHR32:
case FLAGS_SAR32:
case FLAGS_INC32:
case FLAGS_DEC32:
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);
break;
}
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJNS_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
{
case FLAGS_ZN8:
case FLAGS_ADD8:
case FLAGS_SUB8:
case FLAGS_SHL8:
case FLAGS_SHR8:
case FLAGS_SAR8:
case FLAGS_INC8:
case FLAGS_DEC8:
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B);
break;
case FLAGS_ZN16:
case FLAGS_ADD16:
case FLAGS_SUB16:
case FLAGS_SHL16:
case FLAGS_SHR16:
case FLAGS_SAR16:
case FLAGS_INC16:
case FLAGS_DEC16:
jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W);
break;
case FLAGS_ZN32:
case FLAGS_ADD32:
case FLAGS_SUB32:
case FLAGS_SHL32:
case FLAGS_SHR32:
case FLAGS_SAR32:
case FLAGS_INC32:
case FLAGS_DEC32:
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);
break;
}
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJP_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
uop_CALL_FUNC_RESULT(ir, IREG_temp0, PF_SET);
jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJNP_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
uop_CALL_FUNC_RESULT(ir, IREG_temp0, PF_SET);
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJL_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
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);
break;
case FLAGS_ZN16:
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);
break;
case FLAGS_SUB8: case FLAGS_DEC8:
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);
break;
case FLAGS_SUB32: case FLAGS_DEC32:
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);
break;
}
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJNL_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop;
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);
break;
case FLAGS_ZN16:
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);
break;
case FLAGS_SUB8: case FLAGS_DEC8:
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);
break;
case FLAGS_SUB32: case FLAGS_DEC32:
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);
break;
}
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJLE_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop, jump_uop2 = -1;
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);
break;
case FLAGS_SUB16: case FLAGS_DEC16:
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);
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);
break;
}
if (jump_uop2 != -1)
uop_set_jump_dest(ir, jump_uop2);
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
}
static void ropJNLE_common(codeblock_t *block, ir_data_t *ir, uint32_t base_pc, uint32_t offset)
{
int jump_uop, jump_uop2 = -1;
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);
break;
case FLAGS_SUB16: case FLAGS_DEC16:
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);
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);
break;
}
uop_MOV_IMM(ir, IREG_pc, base_pc + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
if (jump_uop2 != -1)
uop_set_jump_dest(ir, jump_uop2);
}
#define ropJ(cond) \
uint32_t ropJ ## cond ## _8(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)(int8_t)fastreadb(cs + op_pc); \
ropJ ## cond ## _common(block, ir, op_pc+1, offset); \
\
return 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); \
ropJ ## cond ## _common(block, ir, op_pc+2, offset); \
\
return 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); \
ropJ ## cond ## _common(block, ir, op_pc+4, offset); \
\
return op_pc+4; \
}
ropJ(O)
ropJ(NO)
ropJ(B)
ropJ(NB)
ropJ(E)
ropJ(NE)
ropJ(BE)
ropJ(NBE)
ropJ(S)
ropJ(NS)
ropJ(P)
ropJ(NP)
ropJ(L)
ropJ(NL)
ropJ(LE)
ropJ(NLE)
uint32_t ropJCXZ(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)(int8_t)fastreadb(cs + op_pc);
int jump_uop;
if (op_32 & 0x200)
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_ECX, 0);
else
jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_CX, 0);
uop_MOV_IMM(ir, IREG_pc, op_pc + 1 + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
return op_pc+1;
}
uint32_t ropLOOP(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)(int8_t)fastreadb(cs + op_pc);
int jump_uop;
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, op_pc + 1 + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
return op_pc+1;
}
uint32_t ropLOOPE(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)(int8_t)fastreadb(cs + op_pc);
int jump_uop, jump_uop2;
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);
}
if (!codegen_flags_changed || (cpu_state.flags_op == FLAGS_UNKNOWN))
{
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
jump_uop2 = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0);
}
else
{
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0);
}
uop_MOV_IMM(ir, IREG_pc, op_pc + 1 + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
uop_set_jump_dest(ir, jump_uop2);
return op_pc+1;
}
uint32_t ropLOOPNE(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)(int8_t)fastreadb(cs + op_pc);
int jump_uop, jump_uop2;
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);
}
if (!codegen_flags_changed || (cpu_state.flags_op == FLAGS_UNKNOWN))
{
uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET);
jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0);
}
else
{
jump_uop2 = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0);
}
uop_MOV_IMM(ir, IREG_pc, op_pc + 1 + offset);
uop_JMP(ir, &block->data[BLOCK_EXIT_OFFSET]);
uop_set_jump_dest(ir, jump_uop);
uop_set_jump_dest(ir, jump_uop2);
return op_pc+1;
}

69
src/codegen_ops_branch.h Normal file
View file

@ -0,0 +1,69 @@
uint32_t ropJB_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJB_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJB_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNB_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNB_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNB_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJBE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJBE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJBE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNBE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNBE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNBE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJL_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJL_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJL_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNL_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNL_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNL_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJLE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJLE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJLE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNLE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNLE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNLE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJO_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJO_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJO_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNO_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNO_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNO_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJP_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJP_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJP_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNP_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNP_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNP_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJS_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNS_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJNS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropJCXZ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropLOOP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropLOOPE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);
uint32_t ropLOOPNE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);

View file

@ -88,9 +88,13 @@ enum
IREG_BH = IREG_EBX + IREG_SIZE_BH,
IREG_flags_res_W = IREG_flags_res + IREG_SIZE_W,
IREG_flags_op1_W = IREG_flags_op1 + IREG_SIZE_W,
IREG_flags_op2_W = IREG_flags_op2 + IREG_SIZE_W,
IREG_flags_res_B = IREG_flags_res + IREG_SIZE_B,
IREG_flags_op1_B = IREG_flags_op1 + IREG_SIZE_B,
IREG_flags_op2_B = IREG_flags_op2 + IREG_SIZE_B,
IREG_temp0_W = IREG_temp0 + IREG_SIZE_W,
IREG_temp1_W = IREG_temp1 + IREG_SIZE_W,
IREG_temp2_W = IREG_temp2 + IREG_SIZE_W,