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>
|
||||
cell_t target = jit->read_cell();
|
||||
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));
|
||||
}
|
||||
|
||||
@ -1195,6 +1194,124 @@ inline void WriteOp_JsGeq(JitWriter *jit)
|
||||
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 ************************************
|
||||
@ -1255,9 +1372,6 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err)
|
||||
AbortCompilation(co);
|
||||
*err = SP_ERR_INVALID_INSTRUCTION;
|
||||
return NULL;
|
||||
} else if (op_c == -2) {
|
||||
/* :TODO: get rid of this block */
|
||||
cip += sizeof(cell_t);
|
||||
} else if (op_c == -1) {
|
||||
switch (op)
|
||||
{
|
||||
|
@ -546,6 +546,17 @@ JITX86::JITX86()
|
||||
OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t);
|
||||
OpAdvTable[OP_PUSH_HEAP_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 */
|
||||
OpAdvTable[OP_LOAD_I] = 0;
|
||||
@ -603,19 +614,6 @@ JITX86::JITX86()
|
||||
OpAdvTable[OP_POP_HEAP_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 */
|
||||
/* :TODO: make an alternate table if USE_UNGEN_OPCODES is on? */
|
||||
OpAdvTable[OP_FILE] = -3;
|
||||
|
@ -187,8 +187,8 @@ typedef enum
|
||||
OP_SYMBOL, // !GEN DEPRECATED
|
||||
OP_SRANGE, // !GEN DEPRECATED
|
||||
OP_JUMP_PRI, // !GEN
|
||||
OP_SWITCH,
|
||||
OP_CASETBL,
|
||||
OP_SWITCH, //DONE
|
||||
OP_CASETBL, //DONE
|
||||
OP_SWAP_PRI, //DONE
|
||||
OP_SWAP_ALT, //DONE
|
||||
OP_PUSH_ADR, //DONE
|
||||
|
@ -618,6 +618,16 @@
|
||||
WriteOp_Jsleq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SWITCH:
|
||||
{
|
||||
WriteOp_Switch(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CASETBL:
|
||||
{
|
||||
WriteOp_Casetbl(jit);
|
||||
break;
|
||||
}
|
||||
#if defined USE_UNGEN_OPCODES
|
||||
#include "ungen_opcode_switch.inc"
|
||||
#endif
|
||||
|
@ -78,6 +78,7 @@
|
||||
#define IA32_MOV_RM_IMM32 0xC7 // encoding is /0
|
||||
#define IA32_CMP_RM_IMM32 0x81 // encoding is /7 <imm32>
|
||||
#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_CMPSB 0xA6 // no extra encoding
|
||||
#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);
|
||||
}
|
||||
|
||||
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,
|
||||
jit_uint8_t dest,
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
jit->write_ubyte(IA32_CMP_EAX_IMM32);
|
||||
|
Loading…
Reference in New Issue
Block a user