added experimental implementation of switch
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40103
This commit is contained in:
parent
39abe7776d
commit
47dadb6cd6
@ -1128,7 +1128,6 @@ inline void WriteOp_Jzer(JitWriter *jit)
|
|||||||
//jz <target>
|
//jz <target>
|
||||||
cell_t target = jit->read_cell();
|
cell_t target = jit->read_cell();
|
||||||
IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
|
IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
|
||||||
IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, target, false));
|
|
||||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, RelocLookup(jit, target, false));
|
IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, RelocLookup(jit, target, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1195,6 +1194,124 @@ inline void WriteOp_JsGeq(JitWriter *jit)
|
|||||||
IA32_Jump_Cond_Imm32(jit, CC_GE, RelocLookup(jit, target, false));
|
IA32_Jump_Cond_Imm32(jit, CC_GE, RelocLookup(jit, target, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void WriteOp_Switch(JitWriter *jit)
|
||||||
|
{
|
||||||
|
cell_t offs = jit->read_cell();
|
||||||
|
cell_t *tbl = (cell_t *)((char *)jit->inbase + offs);
|
||||||
|
|
||||||
|
struct casetbl
|
||||||
|
{
|
||||||
|
cell_t val;
|
||||||
|
cell_t offs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Read the number of cases, then advance by one */
|
||||||
|
cell_t num_cases = *tbl++;
|
||||||
|
if (!num_cases)
|
||||||
|
{
|
||||||
|
/* Special treatment for 0 cases */
|
||||||
|
} else {
|
||||||
|
/* Check if the case layout is fully sequential */
|
||||||
|
casetbl *iter = (casetbl *)(tbl + 1);
|
||||||
|
casetbl *cases = iter;
|
||||||
|
cell_t first = iter[0].val;
|
||||||
|
cell_t last = first;
|
||||||
|
bool sequential = true;
|
||||||
|
for (cell_t i=1; i<num_cases; i++)
|
||||||
|
{
|
||||||
|
if (iter[i].val != ++last)
|
||||||
|
{
|
||||||
|
sequential = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Time to generate.
|
||||||
|
* First check whether the bounds are correct: if (a < LOW || a > HIGH)
|
||||||
|
* This check is valid for both sequential and non-sequential.
|
||||||
|
*/
|
||||||
|
cell_t low_bound = cases[0].val;
|
||||||
|
if (low_bound != 0)
|
||||||
|
{
|
||||||
|
/* negate it so we'll get a lower bound of 0 */
|
||||||
|
//lea ecx, [eax-<LOWER_BOUND>]
|
||||||
|
low_bound = -low_bound;
|
||||||
|
if (low_bound > SCHAR_MIN && low_bound < SCHAR_MAX)
|
||||||
|
{
|
||||||
|
IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound);
|
||||||
|
} else {
|
||||||
|
IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell_t high_bound = abs(cases[0].val - cases[num_cases-1].val);
|
||||||
|
//cmp ecx, <UPPER BOUND BOUND>
|
||||||
|
if (high_bound > SCHAR_MIN && high_bound < SCHAR_MAX)
|
||||||
|
{
|
||||||
|
IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_TMP, high_bound);
|
||||||
|
} else {
|
||||||
|
IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_TMP, high_bound);
|
||||||
|
}
|
||||||
|
//ja <default case>
|
||||||
|
IA32_Jump_Cond_Imm32_Abs(jit, CC_A, RelocLookup(jit, *tbl, false));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Now we've taken the default case out of the way, it's time to do the
|
||||||
|
* full check, which is different for sequential vs. non-sequential.
|
||||||
|
*/
|
||||||
|
if (sequential)
|
||||||
|
{
|
||||||
|
/* we're now theoretically guaranteed to be jumping to a correct offset.
|
||||||
|
* ECX still has the correctly bound offset in it, luckily!
|
||||||
|
* thus, we simply need to relocate ECX and store the cases.
|
||||||
|
*/
|
||||||
|
//shr ecx, 2
|
||||||
|
//add ecx, <case table start>
|
||||||
|
IA32_Shr_Rm_Imm8(jit, AMX_REG_TMP, 2, MOD_REG);
|
||||||
|
jitoffs_t tbl_offs = IA32_Add_Rm_Imm32_Later(jit, AMX_REG_TMP, MOD_REG);
|
||||||
|
IA32_Jump_Rm(jit, AMX_REG_TMP, MOD_MEM_REG);
|
||||||
|
/* The case table starts here. Go back and write the output pointer. */
|
||||||
|
jitoffs_t cur_pos = jit->jit_curpos();
|
||||||
|
jit->setpos(tbl_offs);
|
||||||
|
jit->write_uint32((jit_uint32_t)(jit->outbase + cur_pos));
|
||||||
|
jit->setpos(cur_pos);
|
||||||
|
//now we can write the case table, finally!
|
||||||
|
jit_uint32_t base = (jit_uint32_t)jit->outbase;
|
||||||
|
for (cell_t i=0; i<num_cases; i++)
|
||||||
|
{
|
||||||
|
jit->write_uint32(base + RelocLookup(jit, cases[i].offs, false));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* The slow version. Go through each case and generate a check.
|
||||||
|
* In the future we should replace case tables of more than ~8 cases with a
|
||||||
|
* hash table lookup.
|
||||||
|
*/
|
||||||
|
cell_t val;
|
||||||
|
for (cell_t i=0; i<num_cases; i++)
|
||||||
|
{
|
||||||
|
val = cases[i].val;
|
||||||
|
//cmp eax, <val> OR cmp al, <val>
|
||||||
|
if (val > SCHAR_MIN && val < SCHAR_MAX)
|
||||||
|
{
|
||||||
|
IA32_Cmp_Al_Imm8(jit, val);
|
||||||
|
} else {
|
||||||
|
IA32_Cmp_Eax_Imm32(jit, cases[i].val);
|
||||||
|
}
|
||||||
|
IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, cases[i].offs, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void WriteOp_Casetbl(JitWriter *jit)
|
||||||
|
{
|
||||||
|
/* do nothing here, switch does all ze work */
|
||||||
|
cell_t num_cases = jit->read_cell();
|
||||||
|
|
||||||
|
/* Two cells per case, one extra case for the default jump */
|
||||||
|
num_cases = (num_cases * 2) + 1;
|
||||||
|
jit->inptr += num_cases;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*************************************************
|
/*************************************************
|
||||||
*************************************************
|
*************************************************
|
||||||
* JIT PROPER ************************************
|
* JIT PROPER ************************************
|
||||||
@ -1255,9 +1372,6 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err)
|
|||||||
AbortCompilation(co);
|
AbortCompilation(co);
|
||||||
*err = SP_ERR_INVALID_INSTRUCTION;
|
*err = SP_ERR_INVALID_INSTRUCTION;
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (op_c == -2) {
|
|
||||||
/* :TODO: get rid of this block */
|
|
||||||
cip += sizeof(cell_t);
|
|
||||||
} else if (op_c == -1) {
|
} else if (op_c == -1) {
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
|
@ -546,6 +546,17 @@ JITX86::JITX86()
|
|||||||
OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t);
|
OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t);
|
||||||
OpAdvTable[OP_PUSH_HEAP_C] = sizeof(cell_t);
|
OpAdvTable[OP_PUSH_HEAP_C] = sizeof(cell_t);
|
||||||
OpAdvTable[OP_SYSREQ_C] = sizeof(cell_t);
|
OpAdvTable[OP_SYSREQ_C] = sizeof(cell_t);
|
||||||
|
OpAdvTable[OP_CALL] = sizeof(cell_t);
|
||||||
|
OpAdvTable[OP_JUMP] = sizeof(cell_t);
|
||||||
|
OpAdvTable[OP_JZER] = sizeof(cell_t);
|
||||||
|
OpAdvTable[OP_JNZ] = sizeof(cell_t);
|
||||||
|
OpAdvTable[OP_JEQ] = sizeof(cell_t);
|
||||||
|
OpAdvTable[OP_JNEQ] = sizeof(cell_t);
|
||||||
|
OpAdvTable[OP_JSLESS] = sizeof(cell_t);
|
||||||
|
OpAdvTable[OP_JSLEQ] = sizeof(cell_t);
|
||||||
|
OpAdvTable[OP_JSGRTR] = sizeof(cell_t);
|
||||||
|
OpAdvTable[OP_JSGEQ] = sizeof(cell_t);
|
||||||
|
OpAdvTable[OP_SWITCH] = sizeof(cell_t);
|
||||||
|
|
||||||
/* instructions with 0 parameters */
|
/* instructions with 0 parameters */
|
||||||
OpAdvTable[OP_LOAD_I] = 0;
|
OpAdvTable[OP_LOAD_I] = 0;
|
||||||
@ -603,19 +614,6 @@ JITX86::JITX86()
|
|||||||
OpAdvTable[OP_POP_HEAP_PRI] = 0;
|
OpAdvTable[OP_POP_HEAP_PRI] = 0;
|
||||||
OpAdvTable[OP_SYSREQ_PRI] = 0;
|
OpAdvTable[OP_SYSREQ_PRI] = 0;
|
||||||
|
|
||||||
/* opcodes that need relocation */
|
|
||||||
OpAdvTable[OP_CALL] = -2;
|
|
||||||
OpAdvTable[OP_JUMP] = -2;
|
|
||||||
OpAdvTable[OP_JZER] = -2;
|
|
||||||
OpAdvTable[OP_JNZ] = -2;
|
|
||||||
OpAdvTable[OP_JEQ] = -2;
|
|
||||||
OpAdvTable[OP_JNEQ] = -2;
|
|
||||||
OpAdvTable[OP_JSLESS] = -2;
|
|
||||||
OpAdvTable[OP_JSLEQ] = -2;
|
|
||||||
OpAdvTable[OP_JSGRTR] = -2;
|
|
||||||
OpAdvTable[OP_JSGEQ] = -2;
|
|
||||||
OpAdvTable[OP_SWITCH] = -2;
|
|
||||||
|
|
||||||
/* opcodes that are totally invalid */
|
/* opcodes that are totally invalid */
|
||||||
/* :TODO: make an alternate table if USE_UNGEN_OPCODES is on? */
|
/* :TODO: make an alternate table if USE_UNGEN_OPCODES is on? */
|
||||||
OpAdvTable[OP_FILE] = -3;
|
OpAdvTable[OP_FILE] = -3;
|
||||||
|
@ -187,8 +187,8 @@ typedef enum
|
|||||||
OP_SYMBOL, // !GEN DEPRECATED
|
OP_SYMBOL, // !GEN DEPRECATED
|
||||||
OP_SRANGE, // !GEN DEPRECATED
|
OP_SRANGE, // !GEN DEPRECATED
|
||||||
OP_JUMP_PRI, // !GEN
|
OP_JUMP_PRI, // !GEN
|
||||||
OP_SWITCH,
|
OP_SWITCH, //DONE
|
||||||
OP_CASETBL,
|
OP_CASETBL, //DONE
|
||||||
OP_SWAP_PRI, //DONE
|
OP_SWAP_PRI, //DONE
|
||||||
OP_SWAP_ALT, //DONE
|
OP_SWAP_ALT, //DONE
|
||||||
OP_PUSH_ADR, //DONE
|
OP_PUSH_ADR, //DONE
|
||||||
|
@ -618,6 +618,16 @@
|
|||||||
WriteOp_Jsleq(jit);
|
WriteOp_Jsleq(jit);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OP_SWITCH:
|
||||||
|
{
|
||||||
|
WriteOp_Switch(jit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OP_CASETBL:
|
||||||
|
{
|
||||||
|
WriteOp_Casetbl(jit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
#if defined USE_UNGEN_OPCODES
|
#if defined USE_UNGEN_OPCODES
|
||||||
#include "ungen_opcode_switch.inc"
|
#include "ungen_opcode_switch.inc"
|
||||||
#endif
|
#endif
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
#define IA32_MOV_RM_IMM32 0xC7 // encoding is /0
|
#define IA32_MOV_RM_IMM32 0xC7 // encoding is /0
|
||||||
#define IA32_CMP_RM_IMM32 0x81 // encoding is /7 <imm32>
|
#define IA32_CMP_RM_IMM32 0x81 // encoding is /7 <imm32>
|
||||||
#define IA32_CMP_RM_IMM8 0x83 // encoding is /7 <imm8>
|
#define IA32_CMP_RM_IMM8 0x83 // encoding is /7 <imm8>
|
||||||
|
#define IA32_CMP_AL_IMM32 0x3C // no extra encoding
|
||||||
#define IA32_CMP_EAX_IMM32 0x3D // no extra encoding
|
#define IA32_CMP_EAX_IMM32 0x3D // no extra encoding
|
||||||
#define IA32_CMPSB 0xA6 // no extra encoding
|
#define IA32_CMPSB 0xA6 // no extra encoding
|
||||||
#define IA32_TEST_RM_REG 0x85 // encoding is /r
|
#define IA32_TEST_RM_REG 0x85 // encoding is /r
|
||||||
@ -468,6 +469,17 @@ inline void IA32_Add_Rm_Imm32_Disp8(JitWriter *jit,
|
|||||||
jit->write_int32(val);
|
jit->write_int32(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline jitoffs_t IA32_Add_Rm_Imm32_Later(JitWriter *jit,
|
||||||
|
jit_uint8_t dest,
|
||||||
|
jit_uint8_t mode)
|
||||||
|
{
|
||||||
|
jit->write_ubyte(IA32_ADD_RM_IMM32);
|
||||||
|
jit->write_ubyte(ia32_modrm(mode, 0, dest));
|
||||||
|
jitoffs_t ptr = jit->jit_curpos();
|
||||||
|
jit->write_int32(0);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
inline void IA32_Add_Rm_Imm8_Disp32(JitWriter *jit,
|
inline void IA32_Add_Rm_Imm8_Disp32(JitWriter *jit,
|
||||||
jit_uint8_t dest,
|
jit_uint8_t dest,
|
||||||
jit_int8_t val,
|
jit_int8_t val,
|
||||||
@ -814,6 +826,12 @@ inline void IA32_Jump_Reg(JitWriter *jit, jit_uint8_t reg)
|
|||||||
jit->write_ubyte(ia32_modrm(MOD_REG, 4, reg));
|
jit->write_ubyte(ia32_modrm(MOD_REG, 4, reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void IA32_Jump_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
|
||||||
|
{
|
||||||
|
jit->write_ubyte(IA32_JMP_RM);
|
||||||
|
jit->write_ubyte(ia32_modrm(mode, 4, reg));
|
||||||
|
}
|
||||||
|
|
||||||
inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp)
|
inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp)
|
||||||
{
|
{
|
||||||
jitoffs_t ptr;
|
jitoffs_t ptr;
|
||||||
@ -945,6 +963,12 @@ inline void IA32_Cmp_Rm_Disp8_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t d
|
|||||||
jit->write_byte(imm8);
|
jit->write_byte(imm8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void IA32_Cmp_Al_Imm8(JitWriter *jit, jit_int8_t value)
|
||||||
|
{
|
||||||
|
jit->write_ubyte(IA32_CMP_AL_IMM32);
|
||||||
|
jit->write_byte(value);
|
||||||
|
}
|
||||||
|
|
||||||
inline void IA32_Cmp_Eax_Imm32(JitWriter *jit, jit_int32_t value)
|
inline void IA32_Cmp_Eax_Imm32(JitWriter *jit, jit_int32_t value)
|
||||||
{
|
{
|
||||||
jit->write_ubyte(IA32_CMP_EAX_IMM32);
|
jit->write_ubyte(IA32_CMP_EAX_IMM32);
|
||||||
|
Loading…
Reference in New Issue
Block a user