Alien-LibJIT
view release on metacpan or search on metacpan
libjit/jit/jit-rules-arm.ins view on Meta::CPAN
case 4:
{
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 2);
}
break;
case 8:
{
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 3);
}
break;
case 16:
{
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 4);
}
break;
case 32:
{
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 5);
}
break;
case 64:
{
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 6);
}
break;
case 128:
{
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 7);
}
break;
default:
{
arm_mov_reg_imm8(inst, ARM_WORK, $2);
arm_mul_reg_reg(inst, $1, $1, ARM_WORK);
}
break;
}
}
[reg, reg] -> {
if($1 != $2)
{
arm_mul_reg_reg(inst, $1, $1, $2);
}
else
{
/* Cannot use the same register for both arguments */
arm_mov_reg_reg(inst, ARM_WORK, $2);
arm_mul_reg_reg(inst, $1, $1, ARM_WORK);
}
}
JIT_OP_IDIV:
[any, immzero] -> {
throw_builtin(&inst, func, ARM_CC_AL, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, immu8, if("$2 == 1")] -> {
/* Division by 1. Return the value itself */
}
[reg, immu8, if("($2 > 0) && (((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
/* Handle special cases of small immediate divides: divisions by positive powers of two */
/* NB: (n & (n-1)) == 0 if and only if n is a power of 2 */
/* Move the dividend in the work register, setting the codes (in order to know if it's positive or negative) */
arm_alu_cc_reg(inst, ARM_MOV, ARM_WORK, $1);
/* If the dividend is negative, make it positive (0-x = -x)*/
arm_alu_reg_imm8_cond(inst, ARM_RSB, $1, ARM_WORK, 0, ARM_CC_MI);
switch($2)
{
//Integer divide by shifting
case 2:
{
arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 1);
}
break;
case 4:
{
arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 2);
}
break;
case 8:
{
arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 3);
}
break;
case 16:
{
arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 4);
}
break;
case 32:
{
arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 5);
}
break;
case 64:
{
arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 6);
}
break;
case 128:
{
arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 7);
}
break;
}
/* If the dividend was negative, make it negative again (0-x = -x)*/
arm_alu_reg_imm8_cond(inst, ARM_RSB, $1, $1, 0, ARM_CC_MI);
}
[reg, imm, if("$2 == -1")] -> {
/* Dividing by -1 simply negates */
/*TODO: if the value to be divided by -1 is jit_min_int,
an exception (JIT_RESULT_ARITHMETIC) should probably be thrown */
arm_alu_reg(inst, ARM_MVN, $1, $1);
}
[reg, imm, clobber("r0", "r1")] -> {
/* Every other immediate division:
ARM does not have an integer division operation. It's emulated via software. */
//Put the dividend in the right position
if ($1 != ARM_R0)
arm_mov_reg_reg(inst, ARM_R0, $1);
//Put the divisor in the right position
mov_reg_imm(gen, &inst, ARM_R1, $2);
//Perform the division by calling a function from the runtime ABI
extern int __aeabi_idiv(int numerator, int denominator);
arm_call(inst, __aeabi_idiv);
if($1 != ARM_R0)
{
//Move the result back where it is expected to be
arm_mov_reg_reg(inst, $1, ARM_R0);
}
}
[reg, reg, scratch reg, clobber("r0", "r1")] -> {
/* Every division taking data from two registers:
ARM does not have an integer division operation. It's emulated via software. */
int dividend = $1;
int divisor = $2;
int scratch = $3;
//Put the dividend in the right position
if (dividend != ARM_R0)
{
if (divisor==ARM_R0)
{
//Prevent the divisor from being overwritten
if(dividend != ARM_R1)
{
//The place where the divisor should be is free. Move it there
arm_mov_reg_reg(inst, ARM_R1, divisor);
divisor=1;
}
else
{
/* The dividend is where the divisor should be.
We must use a scratch register to swap them */
arm_mov_reg_reg(inst, scratch, divisor);
divisor=scratch;
}
}
arm_mov_reg_reg(inst, ARM_R0, dividend);
}
if (divisor != ARM_R1)
{
//Put the divisor in the right position
libjit/jit/jit-rules-arm.ins view on Meta::CPAN
arm_test_reg_reg(inst, ARM_CMP, $1, $2);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE_UN);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT_UN);
}
JIT_OP_IGT:
[reg, immu8] -> {
arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE);
}
[reg, reg] -> {
arm_test_reg_reg(inst, ARM_CMP, $1, $2);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE);
}
JIT_OP_IGT_UN:
[reg, immu8] -> {
arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN);
}
[reg, reg] -> {
arm_test_reg_reg(inst, ARM_CMP, $1, $2);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN);
}
JIT_OP_IGE:
[reg, immu8] -> {
arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT);
}
[reg, reg] -> {
arm_test_reg_reg(inst, ARM_CMP, $1, $2);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT);
}
JIT_OP_IGE_UN:
[reg, immu8] -> {
arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE_UN);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT_UN);
}
[reg, reg] -> {
arm_test_reg_reg(inst, ARM_CMP, $1, $2);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE_UN);
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT_UN);
}
/*
* Pointer check opcodes.
*/
JIT_OP_CHECK_NULL: note
[reg] -> {
arm_test_reg_imm8(inst, ARM_CMP, $1, 0);
throw_builtin(&inst, func, ARM_CC_EQ, JIT_RESULT_NULL_REFERENCE);
}
/*
* Function calls.
*/
JIT_OP_CALL:
[] -> {
jit_function_t func = (jit_function_t)(insn->dest);
arm_call(inst, jit_function_to_closure(func));
}
JIT_OP_CALL_TAIL:
[] -> {
jit_function_t func = (jit_function_t)(insn->dest);
arm_pop_frame_tail(inst, 0);
arm_jump(inst, jit_function_to_closure(func));
}
JIT_OP_CALL_INDIRECT:
[] -> {
arm_mov_reg_reg((inst), ARM_LINK, ARM_PC);
arm_mov_reg_reg((inst), ARM_PC, ARM_WORK);
}
JIT_OP_CALL_VTABLE_PTR:
[] -> {
arm_mov_reg_reg((inst), ARM_LINK, ARM_PC);
arm_mov_reg_reg((inst), ARM_PC, ARM_WORK);
}
JIT_OP_CALL_EXTERNAL:
[] -> {
arm_call(inst, (void *)(insn->dest));
}
JIT_OP_RETURN:
[] -> {
jump_to_epilog(gen, &inst, block);
}
JIT_OP_RETURN_INT: /*unary_branch*/
[reg] -> {
int cpu_reg = $1;
if(cpu_reg != ARM_R0)
{
arm_mov_reg_reg(inst, ARM_R0, cpu_reg);
}
jump_to_epilog(gen, &inst, block);
}
JIT_OP_RETURN_LONG: /*unary_branch*/
[imm] -> {
mov_reg_imm(gen, &inst, ARM_R0, ((jit_int *)($1))[0]);
mov_reg_imm(gen, &inst, ARM_R1, ((jit_int *)($1))[1]);
jump_to_epilog(gen, &inst, block);
}
[local] -> {
arm_load_membase(inst, ARM_R0, ARM_FP, $1);
arm_load_membase(inst, ARM_R1, ARM_FP, $1 + 4);
libjit/jit/jit-rules-arm.ins view on Meta::CPAN
}
jump_to_epilog(gen, &inst, block);
}
JIT_OP_SETUP_FOR_NESTED: /*spill_before*/
[] -> {
jit_nint nest_reg = jit_value_get_nint_constant(insn->value1);
if(nest_reg == -1)
{
arm_push_reg(inst, ARM_FP);
}
else
{
arm_mov_reg_reg(inst, _jit_reg_info[nest_reg].cpu_reg, ARM_FP);
}
}
JIT_OP_SETUP_FOR_SIBLING: /*spill_before*/
[] -> {
jit_nint level = jit_value_get_nint_constant(insn->value1);
jit_nint nest_reg = jit_value_get_nint_constant(insn->value2);
int cpu_reg;
if(nest_reg == -1)
{
cpu_reg = ARM_R0;
}
else
{
cpu_reg = _jit_reg_info[nest_reg].cpu_reg;
}
arm_load_membase(inst, cpu_reg, ARM_FP, JIT_APPLY_PARENT_FRAME_OFFSET);
while(level > 0)
{
arm_load_membase(inst, cpu_reg, cpu_reg,
JIT_APPLY_PARENT_FRAME_OFFSET);
--level;
}
if(nest_reg == -1)
{
arm_push_reg(inst, cpu_reg);
}
}
JIT_OP_IMPORT:
[] -> {
/* TODO */
TODO();
}
/*
* Exception handling
*/
JIT_OP_THROW: branch
[reg] -> {
arm_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_nint pc_offset;
_jit_gen_fix_value(func->builder->setjmp_value);
pc_offset = func->builder->setjmp_value->frame_offset +
jit_jmp_catch_pc_offset;
if(func->builder->position_independent)
{
arm_call_imm(inst, 0);
arm_pop_membase(inst, ARM_FP, pc_offset);
}
else
{
int pc = (int) (unsigned char *) arm_inst_get_posn(inst);
arm_mov_membase_imm(inst, ARM_FP, pc_offset, pc, 4, ARM_WORK);
}
}
arm_call(inst, (void *)jit_exception_throw);
}
JIT_OP_LOAD_PC:
[=reg] -> {
if(func->builder->position_independent)
{
arm_call_imm(inst, 0);
arm_pop_reg(inst, $1);
}
else
{
int pc = inst.current;
mov_reg_imm(gen, &inst, $1, pc);
}
}
JIT_OP_ENTER_FINALLY:
[] -> { /*
* The return address is in the link register
* We must save it on the stack in case it will be overwritten by the content
* of the "finally" block.
* In order to respect the ABI of the ARM architecture, that prescribes an 8-byte
* alignment for the stack at a public interface, we save the value twice,
* in order to move the current SP by 8 bytes
* (we could have just saved the value once and then moved the SP by 4 bytes)
*/
arm_push_reg(inst, ARM_LINK);
arm_push_reg(inst, ARM_LINK);
}
JIT_OP_LEAVE_FINALLY: branch
[] -> {
/* The "finally" return address is on the stack (twice, just for padding)*/
arm_pop_reg(inst, ARM_LINK);
arm_pop_reg(inst, ARM_LINK);
arm_return(inst);
}
JIT_OP_CALL_FINALLY: branch
[] -> {
jit_block_t block;
int offset;
block = jit_block_from_label(func, (jit_label_t)(insn->dest));
if(!block)
{
return;
}
if(arm_inst_get_posn(inst) >= arm_inst_get_limit(inst))
{
/* The buffer has overflowed, so don't worry about fixups */
return;
}
if(block->address)
{
/* We already know the address of the block */
arm_call(inst, block->address);
}
else
{
/* Output a placeholder and record on the block's fixup list */
( run in 0.640 second using v1.01-cache-2.11-cpan-f6376fbd888 )