Alien-LibJIT

 view release on metacpan or  search on metacpan

libjit/jit/jit-rules-x86-64.ins  view on Meta::CPAN

	[reg, reg] -> {
		x86_64_add_reg_reg_size(inst, $1, $2, 4);
	}

JIT_OP_ISUB:
	[reg, imm] -> {
		if($2 == 1)
		{
			x86_64_dec_reg_size(inst, $1, 4);
		}
		else
		{
			x86_64_sub_reg_imm_size(inst, $1, $2, 4);
		}
	}
	[reg, local] -> {
		x86_64_sub_reg_membase_size(inst, $1, X86_64_RBP, $2, 4);
	}
	[reg, reg] -> {
		x86_64_sub_reg_reg_size(inst, $1, $2, 4);
	}

JIT_OP_INEG:
	[reg] -> {
		x86_64_neg_reg_size(inst, $1, 4);
	}

JIT_OP_IMUL: commutative
	[reg, immzero] -> {
		x86_64_clear_reg(inst, $1);
	}
	[reg, imm, if("$2 == -1")] -> {
		x86_64_neg_reg_size(inst, $1, 4);
	}
	[reg, imm, if("$2 == 1")] -> {
	}
	[reg, imm, if("$2 == 2")] -> {
		x86_64_add_reg_reg_size(inst, $1, $1, 4);
	}
	[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_64_shl_reg_imm_size(inst, $1, shift, 4);
	}
	[reg, imm] -> {
		x86_64_imul_reg_reg_imm_size(inst, $1, $1, $2, 4);
	}
	[reg, local] -> {
		x86_64_imul_reg_membase_size(inst, $1, X86_64_RBP, $2, 4);
	}
	[reg, reg] -> {
		x86_64_imul_reg_reg_size(inst, $1, $2, 4);
	}

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 */
		jit_int min_int = jit_min_int;
		unsigned char *patch;
		x86_64_cmp_reg_imm_size(inst, $1, min_int, 4);
		patch = inst;
		x86_branch8(inst, X86_CC_NE, 0, 0);
		inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
		x86_patch(patch, inst);
		x86_64_neg_reg_size(inst, $1, 4);
	}
	[reg, imm, scratch reg, if("$2 == 2")] -> {
		/* move the value to be divided to the temporary */
		x86_64_mov_reg_reg_size(inst, $3, $1, 4);
		/* shift the temporary to the 31 bits right */
		/* The result is 1 for negative values and 0 for zero or */
		/* positive values. (corrective value for negatives) */
		x86_64_shr_reg_imm_size(inst, $3, 0x1f, 4);
		/* Add the corrective value to the divident */
		x86_64_add_reg_reg_size(inst, $1, $3, 4);
		/* and do the right shift */
		x86_64_sar_reg_imm_size(inst, $1, 1, 4);
	}
	[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  */
		jit_nuint shift, corr, value = $2 >> 1;
		for(shift = 0; value; value >>= 1)
		{
		    ++shift;
		}
		corr = $2 - 1;
		x86_64_lea_membase_size(inst, $3, $1, corr, 4);
		x86_64_test_reg_reg_size(inst, $1, $1, 4);
		x86_64_cmov_reg_reg_size(inst, X86_CC_S, $1, $3, 1, 4);
		x86_64_sar_reg_imm_size(inst, $1, shift, 4);
	}
	[reg("rax"), imm, scratch dreg, scratch reg("rdx")] -> {
		x86_64_mov_reg_imm_size(inst, $3, $2, 4);
		x86_64_cdq(inst);
		x86_64_idiv_reg_size(inst, $3, 4);
	}
	[reg("rax"), dreg, scratch reg("rdx")] -> {
		jit_int min_int = jit_min_int;
		unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
		x86_64_test_reg_reg_size(inst, $2, $2, 4);
		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_64_cmp_reg_imm_size(inst, $2, -1, 4);
		patch = inst;
		x86_branch8(inst, X86_CC_NE, 0, 0);
		x86_64_cmp_reg_imm_size(inst, $1, min_int, 4);
		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_64_cdq(inst);
		x86_64_idiv_reg_size(inst, $2, 4);
	}

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_64_shr_reg_imm_size(inst, $1, shift, 4);
	}
	[reg("rax"), imm, scratch dreg, scratch reg("rdx")] -> {
		x86_64_mov_reg_imm_size(inst, $3, $2, 4);
		x86_64_clear_reg(inst, X86_64_RDX);
		x86_64_div_reg_size(inst, $3, 4);
	}
	[reg("rax"), dreg, scratch reg("rdx")] -> {
#ifndef JIT_USE_SIGNALS
		unsigned char *patch;
		x86_64_test_reg_reg_size(inst, $2, $2, 4);
		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_64_clear_reg(inst, X86_64_RDX);
		x86_64_div_reg_size(inst, $2, 4);
	}

JIT_OP_IREM: more_space
	[any, immzero] -> {
		inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
	}
	[reg, imm, if("$2 == 1")] -> {
		x86_64_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 */
		jit_int min_int = jit_min_int;
		unsigned char *patch;
		x86_64_cmp_reg_imm_size(inst, $1, min_int, 4);
		patch = inst;
		x86_branch8(inst, X86_CC_NE, 0, 0);
		inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
		x86_patch(patch, inst);
		x86_64_clear_reg(inst, $1);
	}
	[=reg("rdx"), *reg("rax"), imm, scratch dreg, scratch reg("rdx")] -> {
		x86_64_mov_reg_imm_size(inst, $4, $3, 4);
		x86_64_cdq(inst);
		x86_64_idiv_reg_size(inst, $4, 4);
	}
	[=reg("rdx"), *reg("rax"), dreg, scratch reg("rdx")] -> {
		jit_int min_int = jit_min_int;
		unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
		x86_64_test_reg_reg_size(inst, $3, $3, 4);
		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_64_cmp_reg_imm_size(inst, $3, -1, 4);
		patch = inst;
		x86_branch8(inst, X86_CC_NE, 0, 0);
		x86_64_cmp_reg_imm_size(inst, $2, min_int, 4);
		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_64_cdq(inst);
		x86_64_idiv_reg_size(inst, $3, 4);
	}

JIT_OP_IREM_UN: more_space
	[any, immzero] -> {
		inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
	}
	[reg, imm, if("$2 == 1")] -> {
		x86_64_clear_reg(inst, $1);
	}
	[reg, imm, if("($2 & ($2 - 1)) == 0")] -> {
		/* x & (x - 1) is equal to zero if x is a power of 2  */
		x86_64_and_reg_imm_size(inst, $1, $2 - 1, 4);
	}
	[=reg("rdx"), *reg("rax"), imm, scratch dreg, scratch reg("rdx")] -> {
		x86_64_mov_reg_imm_size(inst, $4, $3, 4);
		x86_64_clear_reg(inst, X86_64_RDX);
		x86_64_div_reg_size(inst, $4, 4);
	}
	[=reg("rdx"), *reg("rax"), dreg, scratch reg("rdx")] -> {
#ifndef JIT_USE_SIGNALS
		unsigned char *patch;
		x86_64_test_reg_reg_size(inst, $3, $3, 4);
		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_64_clear_reg(inst, X86_64_RDX);
		x86_64_div_reg_size(inst, $3, 4);
	}

/*
 * 8 byte integer versions
 */

JIT_OP_LADD: commutative
	[reg, imms32] -> {
		if($2 == 1)
		{
			x86_64_inc_reg_size(inst, $1, 8);
		}
		else
		{
			x86_64_add_reg_imm_size(inst, $1, $2, 8);
		}
	}
	[reg, local] -> {
		x86_64_add_reg_membase_size(inst, $1, X86_64_RBP, $2, 8);
	}
	[reg, reg] -> {
		x86_64_add_reg_reg_size(inst, $1, $2, 8);
	}

JIT_OP_LSUB:
	[reg, imms32] -> {
		if($2 == 1)
		{
			x86_64_dec_reg_size(inst, $1, 8);
		}
		else
		{
			x86_64_sub_reg_imm_size(inst, $1, $2, 8);
		}
	}
	[reg, local] -> {
		x86_64_sub_reg_membase_size(inst, $1, X86_64_RBP, $2, 8);
	}
	[reg, reg] -> {
		x86_64_sub_reg_reg_size(inst, $1, $2, 8);
	}

JIT_OP_LNEG:
	[reg] -> {
		x86_64_neg_reg_size(inst, $1, 8);
	}

JIT_OP_LMUL: commutative
	[reg, immzero] -> {
		x86_64_clear_reg(inst, $1);
	}
	[reg, imm, if("$2 == -1")] -> {
		x86_64_neg_reg_size(inst, $1, 8);
	}
	[reg, imm, if("$2 == 1")] -> {
	}
	[reg, imm, if("$2 == 2")] -> {
		x86_64_add_reg_reg_size(inst, $1, $1, 8);
	}
	[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_64_shl_reg_imm_size(inst, $1, shift, 8);
	}
	[reg, imms32] -> {
		x86_64_imul_reg_reg_imm_size(inst, $1, $1, $2, 8);
	}
	[reg, local] -> {
		x86_64_imul_reg_membase_size(inst, $1, X86_64_RBP, $2, 8);
	}
	[reg, reg] -> {
		x86_64_imul_reg_reg_size(inst, $1, $2, 8);
	}

JIT_OP_LDIV: more_space
	[any, immzero] -> {
		inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
	}
	[reg, imm, if("$2 == 1")] -> {
	}
	[reg, imm, scratch reg, if("$2 == -1")] -> {
		/* Dividing by -1 gives an exception if the argument
		   is minint, or simply negates for other values */
		jit_long min_long = jit_min_long;
		unsigned char *patch;
		x86_64_mov_reg_imm_size(inst, $3, min_long, 8);
		x86_64_cmp_reg_reg_size(inst, $1, $3, 8);
		patch = inst;
		x86_branch8(inst, X86_CC_NE, 0, 0);
		inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
		x86_patch(patch, inst);
		x86_64_neg_reg_size(inst, $1, 8);
	}
	[reg, imm, scratch reg, if("$2 == 2")] -> {
		/* move the value to be divided to the temporary */
		x86_64_mov_reg_reg_size(inst, $3, $1, 8);
		/* shift the temporary to the 63 bits right */
		/* The result is 1 for negative values and 0 for zero or */
		/* positive values. (corrective value for negatives) */
		x86_64_shr_reg_imm_size(inst, $3, 0x3f, 8);
		/* Add the corrective value to the divident */
		x86_64_add_reg_reg_size(inst, $1, $3, 8);
		/* and do the right shift */
		x86_64_sar_reg_imm_size(inst, $1, 1, 8);
	}
	[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  */
		jit_nuint shift, value = $2 >> 1;
		for(shift = 0; value; value >>= 1)
		{
		    ++shift;
		}
		if((jit_nuint)$2 <= (jit_nuint)jit_max_uint)
		{
			jit_nuint corr = ($2 - 1);

			x86_64_lea_membase_size(inst, $3, $1, corr, 8);
			x86_64_test_reg_reg_size(inst, $1, $1, 8);
		}
		else
		{
			jit_nuint corr = ($2 - 1);

			if(corr <= (jit_nuint)jit_max_uint)
			{
				x86_64_mov_reg_imm_size(inst, $3, corr, 4);
			}
			else
			{
				x86_64_mov_reg_imm_size(inst, $3, corr, 8);
			}
			x86_64_test_reg_reg_size(inst, $1, $1, 8);
			x86_64_lea_memindex_size(inst, $3, $1, 0, $3, 0, 8);
		}
		x86_64_cmov_reg_reg_size(inst, X86_CC_S, $1, $3, 1, 8);
		x86_64_sar_reg_imm_size(inst, $1, shift, 8);
	}
	[reg("rax"), imm, scratch dreg, scratch reg("rdx")] -> {
		x86_64_mov_reg_imm_size(inst, $3, $2, 8);
		x86_64_cqo(inst);
		x86_64_idiv_reg_size(inst, $3, 8);
	}
	[reg("rax"), dreg, scratch reg("rdx")] -> {
		jit_long min_long = jit_min_long;
		unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
		x86_64_or_reg_reg_size(inst, $2, $2, 8);
		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_64_cmp_reg_imm_size(inst, $2, -1, 8);
		patch = inst;
		x86_branch8(inst, X86_CC_NE, 0, 0);
		x86_64_mov_reg_imm_size(inst, $3, min_long, 8);
		x86_64_cmp_reg_reg_size(inst, $1, $3, 8);
		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_64_cqo(inst);
		x86_64_idiv_reg_size(inst, $2, 8);
	}

JIT_OP_LDIV_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_64_shr_reg_imm_size(inst, $1, shift, 8);
	}
	[reg("rax"), imm, scratch dreg, scratch reg("rdx")] -> {
		x86_64_mov_reg_imm_size(inst, $3, $2, 8);
		x86_64_clear_reg(inst, X86_64_RDX);
		x86_64_div_reg_size(inst, $3, 8);
	}
	[reg("rax"), dreg, scratch reg("rdx")] -> {
#ifndef JIT_USE_SIGNALS
		unsigned char *patch;
		x86_64_test_reg_reg_size(inst, $2, $2, 8);
		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_64_clear_reg(inst, X86_64_RDX);
		x86_64_div_reg_size(inst, $2, 8);
	}

JIT_OP_LREM: more_space
	[any, immzero] -> {
		inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
	}
	[reg, imm, if("$2 == 1")] -> {
		x86_64_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 */
		jit_long min_long = jit_min_long;
		unsigned char *patch;
		x86_64_cmp_reg_imm_size(inst, $1, min_long, 8);
		patch = inst;
		x86_branch8(inst, X86_CC_NE, 0, 0);
		inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
		x86_patch(patch, inst);
		x86_64_clear_reg(inst, $1);
	}
	[=reg("rdx"), *reg("rax"), imm, scratch dreg, scratch reg("rdx")] -> {
		x86_64_mov_reg_imm_size(inst, $4, $3, 8);
		x86_64_cqo(inst);
		x86_64_idiv_reg_size(inst, $4, 8);
	}
	[=reg("rdx"), *reg("rax"), dreg, scratch reg("rdx")] -> {
		jit_long min_long = jit_min_long;
		unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
		x86_64_test_reg_reg_size(inst, $3, $3, 8);
		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_64_mov_reg_imm_size(inst, $1, min_long, 8);
		x86_64_cmp_reg_imm_size(inst, $3, -1, 8);
		patch = inst;
		x86_branch8(inst, X86_CC_NE, 0, 0);
		x86_64_cmp_reg_reg_size(inst, $2, $1, 8);
		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_64_cqo(inst);
		x86_64_idiv_reg_size(inst, $3, 8);
	}

JIT_OP_LREM_UN: more_space
	[any, immzero] -> {
		inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
	}
	[reg, imm, if("$2 == 1")] -> {
		x86_64_clear_reg(inst, $1);
	}
	[reg, imm, scratch reg, if("(((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
		/* x & (x - 1) is equal to zero if x is a power of 2  */
		if(($2 >= jit_min_int) && ($2 <= jit_max_int))
		{
			x86_64_and_reg_imm_size(inst, $1, $2 - 1, 8);
		}
		else
		{
			jit_long temp = $2 - 1;

			x86_64_mov_reg_imm_size(inst, $3, temp, 8);
			x86_64_and_reg_reg_size(inst, $1, $3, 8);
		}
	}
	[=reg("rdx"), *reg("rax"), imm, scratch dreg, scratch reg("rdx")] -> {
		x86_64_mov_reg_imm_size(inst, $4, $3, 8);
		x86_64_clear_reg(inst, X86_64_RDX);
		x86_64_div_reg_size(inst, $4, 8);
	}
	[=reg("rdx"), *reg("rax"), dreg, scratch reg("rdx")] -> {
#ifndef JIT_USE_SIGNALS
		unsigned char *patch;
		x86_64_test_reg_reg_size(inst, $3, $3, 8);
		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_64_clear_reg(inst, X86_64_RDX);
		x86_64_div_reg_size(inst, $3, 8);
	}

/*
 * single precision float versions
 */

JIT_OP_FADD:  commutative
	[xreg, imm] -> {
		_jit_xmm1_reg_imm_size_float32(gen, &inst, XMM1_ADD, $1, (jit_float32 *)$2);
	}
	[xreg, local] -> {
		x86_64_addss_reg_membase(inst, $1, X86_64_RBP, $2);
	}
	[xreg, xreg] -> {
		x86_64_addss_reg_reg(inst, $1, $2);
	}

JIT_OP_FSUB:
	[xreg, imm] -> {
		_jit_xmm1_reg_imm_size_float32(gen, &inst, XMM1_SUB, $1, (jit_float32 *)$2);
	}
	[xreg, xreg] -> {
		x86_64_subss_reg_reg(inst, $1, $2);
	}
	[xreg, local] -> {
		x86_64_subss_reg_membase(inst, $1, X86_64_RBP, $2);
	}

JIT_OP_FMUL: commutative
	[xreg, imm] -> {
		_jit_xmm1_reg_imm_size_float32(gen, &inst, XMM1_MUL, $1, (jit_float32 *)$2);
	}
	[xreg, xreg] -> {
		x86_64_mulss_reg_reg(inst, $1, $2);
	}
	[xreg, local] -> {
		x86_64_mulss_reg_membase(inst, $1, X86_64_RBP, $2);
	}

JIT_OP_FDIV:
	[xreg, imm] -> {
		_jit_xmm1_reg_imm_size_float32(gen, &inst, XMM1_DIV, $1, (jit_float32 *)$2);
	}
	[xreg, xreg] -> {
		x86_64_divss_reg_reg(inst, $1, $2);
	}
	[xreg, local] -> {
		x86_64_divss_reg_membase(inst, $1, X86_64_RBP, $2);
	}

JIT_OP_FABS:
	[xreg] -> {
		/* Simply clear the sign */
		jit_uint values[4] = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff};

		_jit_plops_reg_imm(gen, &inst, XMM_ANDP, $1, &(values[0]));

libjit/jit/jit-rules-x86-64.ins  view on Meta::CPAN

JIT_OP_FFLOOR: more_space
	[=xreg, local, scratch reg] -> {
		inst = x86_64_rounds_reg_membase(inst, $1, $2, $3, X86_ROUND_DOWN);
	}
	[=xreg, xreg, scratch reg] -> {
		inst = x86_64_rounds_reg_reg(inst, $1, $2, $3, X86_ROUND_DOWN);
	}

JIT_OP_DFLOOR: more_space
	[=xreg, local, scratch reg] -> {
		inst = x86_64_roundd_reg_membase(inst, $1, $2, $3, X86_ROUND_DOWN);
	}
	[=xreg, xreg, scratch reg] -> {
		inst = x86_64_roundd_reg_reg(inst, $1, $2, $3, X86_ROUND_DOWN);
	}

JIT_OP_NFFLOOR: more_space
	[freg, scratch reg] -> {
		inst = x86_64_roundnf(inst, $2, X86_ROUND_DOWN);
	}

JIT_OP_FCEIL: more_space
	[=xreg, local, scratch reg] -> {
		inst = x86_64_rounds_reg_membase(inst, $1, $2, $3, X86_ROUND_UP);
	}
	[=xreg, xreg, scratch reg] -> {
		inst = x86_64_rounds_reg_reg(inst, $1, $2, $3, X86_ROUND_UP);
	}

JIT_OP_DCEIL: more_space
	[=xreg, local, scratch reg] -> {
		inst = x86_64_roundd_reg_membase(inst, $1, $2, $3, X86_ROUND_UP);
	}
	[=xreg, xreg, scratch reg] -> {
		inst = x86_64_roundd_reg_reg(inst, $1, $2, $3, X86_ROUND_UP);
	}

JIT_OP_NFCEIL: more_space
	[freg, scratch reg] -> {
		inst = x86_64_roundnf(inst, $2, X86_ROUND_UP);
	}

/*
JIT_OP_FRINT: more_space
	[=xreg, local, scratch reg] -> {
		inst = x86_64_rounds_reg_membase(inst, $1, $2, $3, X86_ROUND_ZERO);
	}
	[=xreg, xreg, scratch reg] -> {
		inst = x86_64_rounds_reg_reg(inst, $1, $2, $3, X86_ROUND_ZERO);
	}
*/

/*
 * 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_64_cmp_reg_membase_size(inst, $1, $1, 0, 8);
#else
		unsigned char *patch;
		x86_64_test_reg_reg_size(inst, $1, $1, 8);
		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);
		inst = x86_64_call_code(inst, (jit_nint)jit_function_to_closure(func));
	}

JIT_OP_CALL_TAIL:
	[] -> {
		jit_function_t func = (jit_function_t)(insn->dest);
		x86_64_mov_reg_reg_size(inst, X86_64_RSP, X86_64_RBP, 8);
		x86_64_pop_reg_size(inst, X86_64_RBP, 8);
		x86_64_jump_to_code(inst, (jit_nint)jit_function_to_closure(func));
	}

JIT_OP_CALL_INDIRECT:
	[] -> {
		x86_64_mov_reg_imm_size(inst, X86_64_RAX, 8, 4);
		x86_64_call_reg(inst, X86_64_SCRATCH);
	}

JIT_OP_CALL_INDIRECT_TAIL:
	[] -> {
		x86_64_mov_reg_reg_size(inst, X86_64_RSP, X86_64_RBP, 8);
		x86_64_pop_reg_size(inst, X86_64_RBP, 8);
		x86_64_jmp_reg(inst, X86_64_SCRATCH);
	}

JIT_OP_CALL_VTABLE_PTR:
	[] -> {
		x86_64_mov_reg_imm_size(inst, X86_64_RAX, 8, 4);
		x86_64_call_reg(inst, X86_64_SCRATCH);
	}

JIT_OP_CALL_VTABLE_PTR_TAIL:
	[] -> {
		x86_64_mov_reg_reg_size(inst, X86_64_RSP, X86_64_RBP, 8);
		x86_64_pop_reg_size(inst, X86_64_RBP, 8);
		x86_64_jmp_reg(inst, X86_64_SCRATCH);
	}

JIT_OP_CALL_EXTERNAL:
	[] -> {
		inst = x86_64_call_code(inst, (jit_nint)(insn->dest));
	}

JIT_OP_CALL_EXTERNAL_TAIL:
	[] -> {
		x86_64_mov_reg_reg_size(inst, X86_64_RSP, X86_64_RBP, 8);
		x86_64_pop_reg_size(inst, X86_64_RBP, 8);
		x86_64_jump_to_code(inst, (jit_nint)(insn->dest));
	}


/*
 * Exception handling.
 */

JIT_OP_THROW: branch
	[reg] -> {
		x86_64_mov_reg_reg_size(inst, X86_64_RDI, $1, 8);
		if(func->builder->setjmp_value != 0)
		{
			jit_nint pc_offset;

			/* 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);
			pc_offset = func->builder->setjmp_value->frame_offset +
							jit_jmp_catch_pc_offset;

			x86_64_lea_membase_size(inst, X86_64_SCRATCH, X86_64_RIP, 0, 8);
			x86_64_mov_membase_reg_size(inst, X86_64_RBP, pc_offset,
										X86_64_SCRATCH, 8);
		}
		inst = x86_64_call_code(inst, (jit_nint)jit_exception_throw);
	}

JIT_OP_RETHROW: manual
	[] -> { /* Not used in native code back ends */ }

JIT_OP_LOAD_PC:
	[=reg] -> {
		x86_64_lea_membase_size(inst, $1, X86_64_RIP, 0, 8);
	}

JIT_OP_LOAD_EXCEPTION_PC: manual
	[] -> { /* Not used in native code back ends */ }

JIT_OP_ENTER_FINALLY:
	[] -> {
		/* The return address is on the stack */
		x86_64_sub_reg_imm_size(inst, X86_64_RSP, 8, 8);
	 }

JIT_OP_LEAVE_FINALLY: branch
	[] -> {
		/* The "finally" return address is on the stack */
		x86_64_add_reg_imm_size(inst, X86_64_RSP, 8, 8);
		x86_64_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)
		{
			inst = x86_64_call_code(inst, (jit_nint)block->address);
		}
		else
		{
			jit_int fixup;

			if(block->fixup_list)
			{
				fixup = _JIT_CALC_FIXUP(block->fixup_list, inst + 1);
			}
			else
			{
				fixup = 0;
			}
			block->fixup_list = (void *)(inst + 1);
			x86_64_call_imm(inst, fixup);
		}
	}

JIT_OP_ADDRESS_OF_LABEL:
	[=reg] -> {
		jit_int *fixup;



( run in 1.139 second using v1.01-cache-2.11-cpan-d7f47b0818f )