Alien-LibJIT
view release on metacpan or search on metacpan
libjit/jit/jit-rules-x86.ins view on Meta::CPAN
*
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
*
* This file is part of the libjit library.
*
* The libjit library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 2.1 of
* the License, or (at your option) any later version.
*
* The libjit library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the libjit library. If not, see
* <http://www.gnu.org/licenses/>.
*/
%regclass reg x86_reg
%regclass breg x86_breg
%regclass freg x86_freg
%lregclass lreg x86_lreg
/*
* Conversion opcodes.
*/
JIT_OP_TRUNC_SBYTE:
[=reg, breg] -> {
x86_widen_reg(inst, $1, $2, 1, 0);
}
JIT_OP_TRUNC_UBYTE:
[=reg, breg] -> {
x86_widen_reg(inst, $1, $2, 0, 0);
}
JIT_OP_TRUNC_SHORT:
[=reg, reg] -> {
x86_widen_reg(inst, $1, $2, 1, 1);
}
JIT_OP_TRUNC_USHORT:
[=reg, reg] -> {
x86_widen_reg(inst, $1, $2, 0, 1);
}
JIT_OP_CHECK_SBYTE: more_space
[reg] -> {
unsigned char *patch1;
unsigned char *patch2;
x86_alu_reg_imm(inst, X86_CMP, $1, -128);
patch1 = inst;
x86_branch8(inst, X86_CC_LE, 0, 1);
x86_alu_reg_imm(inst, X86_CMP, $1, 127);
patch2 = inst;
x86_branch8(inst, X86_CC_LE, 0, 1);
x86_patch(patch1, inst);
inst = throw_builtin(inst, func, JIT_RESULT_OVERFLOW);
x86_patch(patch2, inst);
}
JIT_OP_CHECK_UBYTE: more_space
[reg] -> {
unsigned char *patch1;
x86_alu_reg_imm(inst, X86_CMP, $1, 256);
patch1 = inst;
x86_branch8(inst, X86_CC_LT, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_OVERFLOW);
x86_patch(patch1, inst);
}
JIT_OP_CHECK_SHORT: more_space
[reg] -> {
unsigned char *patch1;
unsigned char *patch2;
x86_alu_reg_imm(inst, X86_CMP, $1, -32768);
patch1 = inst;
x86_branch8(inst, X86_CC_LE, 0, 1);
x86_alu_reg_imm(inst, X86_CMP, $1, 32767);
patch2 = inst;
x86_branch8(inst, X86_CC_LE, 0, 1);
x86_patch(patch1, inst);
inst = throw_builtin(inst, func, JIT_RESULT_OVERFLOW);
x86_patch(patch2, inst);
}
JIT_OP_CHECK_USHORT: more_space
[reg] -> {
unsigned char *patch1;
x86_alu_reg_imm(inst, X86_CMP, $1, 65536);
patch1 = inst;
x86_branch8(inst, X86_CC_LT, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_OVERFLOW);
x86_patch(patch1, inst);
}
JIT_OP_CHECK_INT, JIT_OP_CHECK_UINT: copy, more_space
[reg] -> {
unsigned char *patch1;
x86_alu_reg_imm(inst, X86_CMP, $1, 0);
patch1 = inst;
x86_branch8(inst, X86_CC_GE, 0, 1);
inst = throw_builtin(inst, func, JIT_RESULT_OVERFLOW);
x86_patch(patch1, inst);
}
JIT_OP_LOW_WORD:
[=reg, imm] -> {
jit_uint value = ((jit_uint *)($2))[0];
x86_mov_reg_imm(inst, $1, value);
}
[=reg, local] -> {
x86_mov_reg_membase(inst, $1, X86_EBP, $2, 4);
}
[=reg, lreg] -> {
if($1 != $2)
{
x86_mov_reg_reg(inst, $1, $2, 4);
}
}
JIT_OP_EXPAND_INT:
[=lreg, reg] -> {
if($1 != $2)
{
x86_mov_reg_reg(inst, $1, $2, 4);
}
x86_mov_reg_reg(inst, %1, $1, 4);
x86_shift_reg_imm(inst, X86_SAR, %1, 31);
}
JIT_OP_EXPAND_UINT:
[=lreg, reg] -> {
if($1 != $2)
{
x86_mov_reg_reg(inst, $1, $2, 4);
}
x86_clear_reg(inst, %1);
}
JIT_OP_FLOAT32_TO_INT, JIT_OP_FLOAT64_TO_INT, JIT_OP_NFLOAT_TO_INT: stack
[=reg, freg] -> {
/* allocate space on the stack for 2 shorts and 1 int */
x86_alu_reg_imm(inst, X86_SUB, X86_ESP, 8);
/* store FPU control word */
x86_fnstcw_membase(inst, X86_ESP, 0);
/* set "round toward zero" mode */
x86_mov_reg_membase(inst, $1, X86_ESP, 0, 2);
x86_alu_reg16_imm(inst, X86_OR, $1, 0xc00);
x86_mov_membase_reg(inst, X86_ESP, 2, $1, 2);
x86_fldcw_membase(inst, X86_ESP, 2);
/* convert float to int */
x86_fist_pop_membase(inst, X86_ESP, 4, 0);
/* restore FPU control word */
x86_fldcw_membase(inst, X86_ESP, 0);
/* move result to the destination */
x86_mov_reg_membase(inst, $1, X86_ESP, 4, 4);
/* restore the stack */
x86_alu_reg_imm(inst, X86_ADD, X86_ESP, 8);
}
JIT_OP_FLOAT32_TO_LONG, JIT_OP_FLOAT64_TO_LONG, JIT_OP_NFLOAT_TO_LONG: stack
[=lreg, freg] -> {
libjit/jit/jit-rules-x86.ins view on Meta::CPAN
break;
case 0x02000000:
{
x86_shift_reg_imm(inst, X86_SHL, $1, 25);
}
break;
case 0x04000000:
{
x86_shift_reg_imm(inst, X86_SHL, $1, 26);
}
break;
case 0x08000000:
{
x86_shift_reg_imm(inst, X86_SHL, $1, 27);
}
break;
case 0x10000000:
{
x86_shift_reg_imm(inst, X86_SHL, $1, 28);
}
break;
case 0x20000000:
{
x86_shift_reg_imm(inst, X86_SHL, $1, 29);
}
break;
case 0x40000000:
{
x86_shift_reg_imm(inst, X86_SHL, $1, 30);
}
break;
case (jit_nint)0x80000000:
{
x86_shift_reg_imm(inst, X86_SHL, $1, 31);
}
break;
default:
{
x86_imul_reg_reg_imm(inst, $1, $1, $2);
}
break;
}
}
[reg, local] -> {
x86_imul_reg_membase(inst, $1, X86_EBP, $2);
}
[reg, reg] -> {
x86_imul_reg_reg(inst, $1, $2);
}
JIT_OP_IDIV: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
}
[reg, imm, if("$2 == -1")] -> {
/* Dividing by -1 gives an exception if the argument
is minint, or simply negates for other values */
unsigned char *patch;
x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_neg_reg(inst, $1);
}
[reg, imm, scratch reg, if("$2 == 2")] -> {
x86_mov_reg_reg(inst, $3, $1, 4);
x86_shift_reg_imm(inst, X86_SHR, $3, 0x1f);
x86_alu_reg_reg(inst, X86_ADD, $1, $3);
x86_shift_reg_imm(inst, X86_SAR, $1, 1);
}
[reg, imm, scratch reg, if("($2 > 0) && (((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
/* x & (x - 1) is equal to zero if x is a power of 2 */
/* This code is generated by gcc for pentium. */
/* We use this code because cmov is not available on all i386 cpus */
jit_nuint shift, temp, value = $2 >> 1;
for(shift = 0; value; value >>= 1)
{
++shift;
}
temp = 32 - shift;
x86_mov_reg_reg(inst, $3, $1, 4);
x86_shift_reg_imm(inst, X86_SAR, $3, 0x1f);
x86_shift_reg_imm(inst, X86_SHR, $3, temp);
x86_alu_reg_reg(inst, X86_ADD, $1, $3);
x86_shift_reg_imm(inst, X86_SAR, $1, shift);
}
[reg("eax"), imm, scratch reg, scratch reg("edx")] -> {
x86_mov_reg_imm(inst, $3, $2);
x86_cdq(inst);
x86_div_reg(inst, $3, 1);
}
[reg("eax"), reg, scratch reg("edx")] -> {
unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
x86_alu_reg_reg(inst, X86_OR, $2, $2);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_alu_reg_imm(inst, X86_CMP, $2, -1);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
patch2 = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_patch(patch2, inst);
x86_cdq(inst);
x86_div_reg(inst, $2, 1);
}
JIT_OP_IDIV_UN: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
}
[reg, imm, if("(((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
/* x & (x - 1) is equal to zero if x is a power of 2 */
jit_nuint shift, value = $2 >> 1;
for(shift = 0; value; value >>= 1)
{
++shift;
}
x86_shift_reg_imm(inst, X86_SHR, $1, shift);
}
[reg("eax"), imm, scratch reg, scratch reg("edx")] -> {
x86_mov_reg_imm(inst, $3, $2);
x86_clear_reg(inst, X86_EDX);
x86_div_reg(inst, $3, 0);
}
[reg("eax"), reg, scratch reg("edx")] -> {
#ifndef JIT_USE_SIGNALS
unsigned char *patch;
x86_alu_reg_reg(inst, X86_OR, $2, $2);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_clear_reg(inst, X86_EDX);
x86_div_reg(inst, $2, 0);
}
JIT_OP_IREM: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
x86_clear_reg(inst, $1);
}
[reg, imm, if("$2 == -1")] -> {
/* Dividing by -1 gives an exception if the argument
is minint, or simply gives a remainder of zero */
unsigned char *patch;
x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_clear_reg(inst, $1);
}
[=reg("edx"), *reg("eax"), imm, scratch reg, scratch reg("edx")] -> {
x86_mov_reg_imm(inst, $4, $3);
x86_cdq(inst);
x86_div_reg(inst, $4, 1);
}
[=reg("edx"), *reg("eax"), reg, scratch reg("edx")] -> {
unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
x86_alu_reg_reg(inst, X86_OR, $3, $3);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_alu_reg_imm(inst, X86_CMP, $3, -1);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
x86_alu_reg_imm(inst, X86_CMP, $2, jit_min_int);
patch2 = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_patch(patch2, inst);
x86_cdq(inst);
x86_div_reg(inst, $3, 1);
}
JIT_OP_IREM_UN: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
x86_clear_reg(inst, $1);
}
[reg, imm, if("(((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
/* x & (x - 1) is equal to zero if x is a power of 2 */
x86_alu_reg_imm(inst, X86_AND, $1, $2 - 1);
}
[=reg("edx"), *reg("eax"), imm, scratch reg, scratch reg("edx")] -> {
x86_mov_reg_imm(inst, $4, $3);
x86_clear_reg(inst, X86_EDX);
x86_div_reg(inst, $4, 0);
}
[=reg("edx"), *reg("eax"), reg, scratch reg("edx")] -> {
#ifndef JIT_USE_SIGNALS
unsigned char *patch;
x86_alu_reg_reg(inst, X86_OR, $3, $3);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_clear_reg(inst, X86_EDX);
x86_div_reg(inst, $3, 0);
}
JIT_OP_INEG:
[reg] -> {
x86_neg_reg(inst, $1);
}
JIT_OP_LADD: commutative
[lreg, imm] -> {
jit_int value1 = ((jit_int *)($2))[0];
jit_int value2 = ((jit_int *)($2))[1];
if(value1 != 0)
{
x86_alu_reg_imm(inst, X86_ADD, $1, value1);
x86_alu_reg_imm(inst, X86_ADC, %1, value2);
}
else
{
x86_alu_reg_imm(inst, X86_ADD, %1, value2);
}
}
[lreg, local] -> {
x86_alu_reg_membase(inst, X86_ADD, $1, X86_EBP, $2);
x86_alu_reg_membase(inst, X86_ADC, %1, X86_EBP, $2 + 4);
}
[lreg, lreg] -> {
x86_alu_reg_reg(inst, X86_ADD, $1, $2);
x86_alu_reg_reg(inst, X86_ADC, %1, %2);
}
JIT_OP_LSUB:
[lreg, imm] -> {
jit_int value1 = ((jit_int *)($2))[0];
jit_int value2 = ((jit_int *)($2))[1];
if(value1 != 0)
{
x86_alu_reg_imm(inst, X86_SUB, $1, value1);
x86_alu_reg_imm(inst, X86_SBB, %1, value2);
}
else
{
x86_alu_reg_imm(inst, X86_SUB, %1, value2);
}
}
[lreg, local] -> {
x86_alu_reg_membase(inst, X86_SUB, $1, X86_EBP, $2);
x86_alu_reg_membase(inst, X86_SBB, %1, X86_EBP, $2 + 4);
}
[lreg, lreg] -> {
x86_alu_reg_reg(inst, X86_SUB, $1, $2);
x86_alu_reg_reg(inst, X86_SBB, %1, %2);
}
JIT_OP_LNEG:
[lreg] -> {
/* TODO: gcc generates the first variant while
libjit/jit/jit-rules-x86.ins view on Meta::CPAN
x86_alu_reg_reg(inst, X86_SBB, $1, $1);
x86_alu_reg_reg(inst, X86_AND, $1, $2);
x86_alu_reg_reg(inst, X86_ADD, $1, $3);
}
JIT_OP_ISIGN:
[=reg, imm] -> {
if($2 < 0)
{
x86_mov_reg_imm(inst, $1, -1);
}
else if($2 > 0)
{
x86_mov_reg_imm(inst, $1, 1);
}
else
{
x86_clear_reg(inst, $1);
}
}
[=+reg, +reg] -> {
x86_clear_reg(inst, $1);
x86_test_reg_reg(inst, $2, $2);
x86_set_reg(inst, X86_CC_NZ, $1, 0);
x86_shift_reg_imm(inst, X86_SAR, $2, 31);
x86_alu_reg_reg(inst, X86_OR, $1, $2);
}
JIT_OP_LSIGN:
[=reg, imm] -> {
jit_long value = *((jit_long *)($2));
if(value < 0)
{
x86_mov_reg_imm(inst, $1, -1);
}
else if(value > 0)
{
x86_mov_reg_imm(inst, $1, 1);
}
else
{
x86_clear_reg(inst, $1);
}
}
[=+reg, +lreg] -> {
x86_clear_reg(inst, $1);
x86_alu_reg_reg(inst, X86_OR, $2, %2);
x86_set_reg(inst, X86_CC_NZ, $1, 0);
x86_shift_reg_imm(inst, X86_SAR, %2, 31);
x86_alu_reg_reg(inst, X86_OR, $1, %2);
}
/*
* Pointer check opcodes.
*/
JIT_OP_CHECK_NULL: note
[reg] -> {
#if 0 && defined(JIT_USE_SIGNALS)
/* if $1 contains NULL this generates SEGV and the signal
handler will throw the exception */
x86_alu_reg_membase(inst, X86_CMP, $1, $1, 0);
#else
unsigned char *patch;
x86_alu_reg_reg(inst, X86_OR, $1, $1);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_NULL_REFERENCE);
x86_patch(patch, inst);
#endif
}
/*
* Function calls.
*/
JIT_OP_CALL:
[] -> {
jit_function_t func = (jit_function_t)(insn->dest);
x86_call_code(inst, jit_function_to_closure(func));
}
JIT_OP_CALL_TAIL:
[] -> {
jit_function_t func = (jit_function_t)(insn->dest);
x86_mov_reg_reg(inst, X86_ESP, X86_EBP, sizeof(void *));
x86_pop_reg(inst, X86_EBP);
x86_jump_code(inst, jit_function_to_closure(func));
}
JIT_OP_CALL_INDIRECT:
[] -> {
x86_call_reg(inst, X86_EAX);
}
JIT_OP_CALL_INDIRECT_TAIL:
[] -> {
x86_mov_reg_reg(inst, X86_ESP, X86_EBP, sizeof(void *));
x86_pop_reg(inst, X86_EBP);
x86_jump_reg(inst, X86_EAX);
}
JIT_OP_CALL_VTABLE_PTR:
[] -> {
x86_call_reg(inst, X86_EAX);
}
JIT_OP_CALL_VTABLE_PTR_TAIL:
[] -> {
x86_mov_reg_reg(inst, X86_ESP, X86_EBP, sizeof(void *));
x86_pop_reg(inst, X86_EBP);
x86_jump_reg(inst, X86_EAX);
}
JIT_OP_CALL_EXTERNAL:
[] -> {
x86_call_code(inst, (void *)(insn->dest));
}
JIT_OP_CALL_EXTERNAL_TAIL:
[] -> {
x86_mov_reg_reg(inst, X86_ESP, X86_EBP, sizeof(void *));
x86_pop_reg(inst, X86_EBP);
x86_jump_code(inst, (void *)(insn->dest));
}
JIT_OP_RETURN:
[] -> {
libjit/jit/jit-rules-x86.ins view on Meta::CPAN
sizeof(void *));
}
else if(parent->in_global_register)
{
x86_mov_reg_reg(inst, cpu_reg,
_jit_reg_info[parent->global_reg].cpu_reg,
sizeof(void *));
}
else
{
_jit_gen_fix_value(parent);
x86_mov_reg_membase(inst, cpu_reg, X86_EBP,
parent->frame_offset, sizeof(void *));
}
while(level > 0)
{
gen->ptr = inst;
_jit_gen_check_space(gen, 16);
x86_mov_reg_membase(inst, cpu_reg, cpu_reg, 0, sizeof(void *));
--level;
}
if(nest_reg == -1)
{
x86_push_reg(inst, cpu_reg);
}
}
JIT_OP_IMPORT: manual
[] -> {
unsigned char *inst;
int reg;
jit_nint level = jit_value_get_nint_constant(insn->value2);
_jit_gen_fix_value(insn->value1);
reg = _jit_regs_load_value
(gen, func->builder->parent_frame, 1, 0);
inst = gen->ptr;
_jit_gen_check_space(gen, 32 + level * 8);
reg = _jit_reg_info[reg].cpu_reg;
while(level > 0)
{
x86_mov_reg_membase(inst, reg, reg, 0, sizeof(void *));
--level;
}
if(insn->value1->frame_offset != 0)
{
x86_alu_reg_imm(inst, X86_ADD, reg, insn->value1->frame_offset);
}
gen->ptr = inst;
}
/*
* Exception handling.
*/
JIT_OP_THROW: branch
[reg] -> {
x86_push_reg(inst, $1);
if(func->builder->setjmp_value != 0)
{
/* We have a "setjmp" block in the current function,
so we must record the location of the throw first */
_jit_gen_fix_value(func->builder->setjmp_value);
if(func->builder->position_independent)
{
x86_call_imm(inst, 0);
x86_pop_membase(inst, X86_EBP,
func->builder->setjmp_value->frame_offset
+ jit_jmp_catch_pc_offset);
}
else
{
int pc = (int) inst;
x86_mov_membase_imm(inst, X86_EBP,
func->builder->setjmp_value->frame_offset
+ jit_jmp_catch_pc_offset, pc, 4);
}
}
x86_call_code(inst, (void *)jit_exception_throw);
}
JIT_OP_RETHROW: manual
[] -> { /* Not used in native code back ends */ }
JIT_OP_LOAD_PC:
[=reg] -> {
if(func->builder->position_independent)
{
x86_call_imm(inst, 0);
x86_pop_reg(inst, $1);
}
else
{
int pc = (int) inst;
x86_mov_reg_imm(inst, $1, pc);
}
}
JIT_OP_LOAD_EXCEPTION_PC: manual
[] -> { /* Not used in native code back ends */ }
JIT_OP_ENTER_FINALLY: manual
[] -> { /* Nothing to do here: return address on the stack */ }
JIT_OP_LEAVE_FINALLY: branch
[] -> {
/* The "finally" return address is on the stack */
x86_ret(inst);
}
JIT_OP_CALL_FINALLY: branch
[] -> {
jit_block_t block;
block = jit_block_from_label(func, (jit_label_t)(insn->dest));
if(!block)
{
return;
}
if(block->address)
{
x86_call_code(inst, block->address);
}
else
{
x86_call_imm(inst, block->fixup_list);
block->fixup_list = (void *)(inst - 4);
}
}
JIT_OP_ENTER_FILTER: manual
[] -> {
/* TODO */
TODO();
}
JIT_OP_LEAVE_FILTER: manual
[] -> {
( run in 1.437 second using v1.01-cache-2.11-cpan-d7f47b0818f )