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 )