Alien-LibJIT

 view release on metacpan or  search on metacpan

libjit/jit/jit-gen-arm.h  view on Meta::CPAN

 * Move an immediate value into a register.  This is hard because
 * ARM lacks an instruction to load a 32-bit immediate value directly.
 * We handle the simple cases and then bail out to a function for the rest.
 */
#define	arm_mov_reg_imm8(inst,reg,imm)	\
			do { \
				arm_alu_reg_imm8((inst), ARM_MOV, (reg), 0, (imm)); \
			} while (0)
#define	arm_mov_reg_imm8_rotate(inst,reg,imm,rotate)	\
			do { \
				arm_alu_reg_imm8_rotate((inst), ARM_MOV, (reg), \
										0, (imm), (rotate)); \
			} while (0)
extern void _arm_mov_reg_imm
	(arm_inst_buf *inst, int reg, int value, int execute_prefix);
extern int arm_is_complex_imm(int value);

/**
 * Moves the immediate value imm into register reg.
 *
 * In case imm is > 255, it builds the value one byte at a time, by calling _arm_mov_reg_imm
 * This is done by using a big number of instruction.
 * In that case, using mov_reg_imm (defined in jit-rules-arm.c is probably a better idea, when possible
 */
#define	arm_mov_reg_imm(inst,reg,imm)	\
			do { \
				int __imm = (int)(imm); \
				if(__imm >= 0 && __imm < 256) \
				{ \
					arm_mov_reg_imm8((inst), (reg), __imm); \
				} \
				else if((reg) == ARM_PC) \
				{ \
					_arm_mov_reg_imm \
						(&(inst), ARM_WORK, __imm, arm_execute); \
					arm_mov_reg_reg((inst), ARM_PC, ARM_WORK); \
				} \
				else if(__imm > -256 && __imm < 0) \
				{ \
					arm_mov_reg_imm8((inst), (reg), ~(__imm)); \
					arm_alu_reg((inst), ARM_MVN, (reg), (reg)); \
				} \
				else \
				{ \
					_arm_mov_reg_imm(&(inst), (reg), __imm, arm_execute); \
				} \
			} while (0)

#define ARM_NOBASEREG (-1)

/**
 * LDR (Load Register), LDRB (Load Register Byte)
 * Load the content of the memory area of size "size" at position basereg+disp+(indexreg<<shift) into the 32-bit "reg", with zero-extension.
 * "scratchreg" is a scratch register that has to be asked to the register allocator; it is 
 * used only when disp!=0; if disp==0, it can have whatever value, since it won't be used
 */
#define arm_mov_reg_memindex(inst,reg,basereg,disp,indexreg,shift,size,scratchreg)	\
do {	\
	if (basereg==ARM_NOBASEREG)	\
	{	\
		fprintf(stderr, "TODO(NOBASEREG) at %s, %d\n", __FILE__, (int)__LINE__);	\
	}	\
	else	\
	{	\
		/* Add the displacement (only if needed)*/\
		int tempreg=(basereg);	\
		if (disp!=0)	\
		{	\
			tempreg=(scratchreg);	\
			assert(tempreg!=basereg);	\
			assert(tempreg!=indexreg);	\
			arm_alu_reg_imm((inst), ARM_ADD, (tempreg), (basereg), (disp)); \
		}	\
		/* Load the content, depending on its size */	\
		switch ((size)) {	\
			case 1: arm_load_memindex_either(inst,reg,(tempreg),indexreg,shift,0x00400000); break;	\
			case 2: arm_load_memindex_either(inst,reg,tempreg,indexreg,shift,0);	\
				arm_shift_reg_imm8((inst), ARM_SHL, (reg), (reg), 16);	\
				arm_shift_reg_imm8((inst), ARM_SHR, (reg), (reg), 16);	\
				break; \
			case 4: arm_load_memindex_either(inst,reg,tempreg,indexreg,shift,0); break;	\
			default: assert (0);	\
		}	\
	}	\
} while (0)

/**
 * Store the content of "reg" into a memory area of size "size" at position basereg+disp+(indexreg<<shift)
 * NB: the scratch register has to be asked to the register allocator.
 *     It can't be ARM_WORK, since it's already used
 */
#define arm_mov_memindex_reg(inst,basereg,disp,indexreg,shift,reg,size,scratchreg)	\
do {	\
	if (basereg==ARM_NOBASEREG)	\
	{	\
		fprintf(stderr, "TODO(NOBASEREG) at %s, %d\n", __FILE__, (int)__LINE__);	\
	}	\
	else	\
	{	\
		arm_shift_reg_imm8((inst), ARM_SHL, (ARM_WORK), (indexreg), (shift));	\
		arm_alu_reg_reg((inst), ARM_ADD, (scratchreg), (basereg), ARM_WORK);	\
		arm_mov_membase_reg((inst),(scratchreg),(disp),(reg),(size))	\
	}	\
} while (0);

/*
 * Stores the content of register "reg" in memory, at position "mem" with size "size"
 * NB: destroys the content of ARM_WORK
 */
#define arm_mov_mem_reg(inst,mem,reg,size)	\
do {	\
	arm_mov_reg_imm((inst), ARM_WORK, (mem));	\
	switch ((size)) {	\
		case 1: arm_store_membase_byte((inst), (reg), ARM_WORK, 0); break;	\
		case 2: arm_store_membase_short((inst), (reg), ARM_WORK, 0); break;	\
		case 4: arm_store_membase((inst), (reg), ARM_WORK, 0); break;	\
		default: jit_assert(0);	\
	}	\
} while (0)

/*
 * Stores the content of "imm" in memory, at position "mem" with size "size". Uses a scratch register (scratchreg),
 * that has to be asked to the register allocator via the [scratch reg] parameter in the definition of the OPCODE.
 * NB: destroys the content of ARM_WORK
 */
#define arm_mov_mem_imm(inst,mem,imm,size,scratchreg)	\
do {	\
	arm_mov_reg_imm((inst), (scratchreg), (imm));	\
	arm_mov_reg_imm((inst), ARM_WORK, (mem));	\
	switch ((size)) {	\
		case 1: arm_store_membase_byte((inst), (scratchreg), ARM_WORK, 0); break;	\
		case 2: arm_store_membase_short((inst), (scratchreg), ARM_WORK, 0); break;	\
		case 4: arm_store_membase((inst), (scratchreg), ARM_WORK, 0); break;	\
		default: assert(0);	\
	}	\
} while (0)

/**
 * Set "size" bytes at position basereg+disp at the value of imm
 * NB: destroys the content of scratchreg. A good choice for scratchreg is ARM_WORK,
 * unless the value of disp is too big to be handled by arm_store_membase_either. In that case,
 * it's better to require the allocation of a scratch reg by adding the parameter [scratch reg] at the end
 * of the parameters of the rule inside jit-rules-arm.ins that's calling this function.
 */
#define arm_mov_membase_imm(inst,basereg,disp,imm,size,scratchreg)	\
do {	\
	arm_mov_reg_imm((inst), (scratchreg), imm);	\
	arm_mov_membase_reg((inst), (basereg), (disp), (scratchreg), (size));	\
} while(0);

/**
 * Set "size" bytes at position basereg+disp at the value of reg
 * NB: might destroy the content of ARM_WORK because of arm_store_membase
 */
#define arm_mov_membase_reg(inst,basereg,disp,reg,size)	\
do {	\



( run in 0.488 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )