Alien-LibJIT

 view release on metacpan or  search on metacpan

libjit/jit/jit-rules-arm.c  view on Meta::CPAN

			regset |= (1 << reg);
		}
	}

	/* Apply fixups for blocks that jump to the epilog */
	fixup = (void **)(gen->epilog_fixup);
	while(fixup != 0)
	{
		offset = (((jit_nint)(fixup[0])) & 0x00FFFFFF) << 2;
		if(!offset)
		{
			next = 0;
		}
		else
		{
			next = (void **)(((unsigned char *)fixup) - offset);
		}
		arm_patch(inst, fixup, arm_inst_get_posn(inst));
		fixup = next;
	}
	gen->epilog_fixup = 0;

	/* Pop the local stack frame and return */
	arm_pop_frame(inst, regset);
	jit_gen_save_inst_ptr(gen, inst);

	/* Flush the remainder of the constant pool */
	flush_constants(gen, 1);
}

#if 0
/*
 * The ARM backend does not need this function because it uses
 * _jit_create_indirector() instead.
 */
void *_jit_gen_redirector(jit_gencode_t gen, jit_function_t func)
{
	void *ptr, *entry;
	arm_inst_buf inst;
	jit_gen_load_inst_ptr(gen, inst);
	ptr = (void *)&(func->entry_point);
	entry = gen->ptr;
	arm_load_membase(inst, ARM_WORK, ARM_PC, 0);
	arm_load_membase(inst, ARM_PC, ARM_WORK, 0);
	arm_inst_add(inst, (unsigned int)ptr);
	jit_gen_save_inst_ptr(gen, inst);
	return entry;
}
#endif 
/*
 * Setup or teardown the ARM code output process.
 */
#define	jit_cache_setup_output(needed)	\
	arm_inst_buf inst; \
	jit_gen_load_inst_ptr(gen, inst)
#define	jit_cache_end_output()	\
	jit_gen_save_inst_ptr(gen, inst)

/** 
 * Spill the content of register "reg" (and "other_reg", if it's different from -1) 
 * into the global register or the memory area associated with "value"
 * NB: it doesn't set value->in_global_register or value->in_frame. The caller has to
 * take care of that.
 */
void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
						int other_reg, jit_value_t value)
{
	int offset;

	/* Make sure that we have sufficient space */
	jit_cache_setup_output(32);
	if(flush_if_too_far(gen))
	{
		jit_gen_load_inst_ptr(gen, inst);
	}

	/* Output an appropriate instruction to spill the value */
	if(value->has_global_register)
	{
		if (IS_FLOAT_REG(reg))
		{
			printf("TODO:Copy from float reg to global reg is not handled properly in %s\n", __FILE__);
			abort();
		}
		else
		{
			arm_mov_reg_reg(inst, _jit_reg_info[value->global_reg].cpu_reg, _jit_reg_info[reg].cpu_reg);
		}
	}
	else
	{
		_jit_gen_fix_value(value);
		offset = (int)(value->frame_offset);
		if(IS_WORD_REG(reg))
		{
			arm_store_membase(inst, reg, ARM_FP, offset);
			if(other_reg != -1)
			{
				/* Spill the other word register in a pair */
				offset += sizeof(void *);
				arm_store_membase(inst, other_reg, ARM_FP, offset);
			}
		}
		else if(jit_type_normalize(value->type)->kind == JIT_TYPE_FLOAT32)
		{
			arm_store_membase_float32(inst, _jit_reg_info[value->reg].cpu_reg, ARM_FP, offset);
		}
		else
		{
			arm_store_membase_float64(inst, _jit_reg_info[value->reg].cpu_reg, ARM_FP, offset);
		}
	}

	/* End the code output process */
	jit_cache_end_output();
}

void _jit_gen_free_reg(jit_gencode_t gen, int reg,
					   int other_reg, int value_used)
{
	/* We don't have to do anything to free ARM registers */
}

/*
 * Loads the content of the value @var{value} into register @var{reg} and (if needed) @var{other_reg}
 */
void _jit_gen_load_value
	(jit_gencode_t gen, int reg, int other_reg, jit_value_t value)
{
	int offset;

	/* Make sure that we have sufficient space */
	jit_cache_setup_output(32);
	if(flush_if_too_far(gen))
	{
		jit_gen_load_inst_ptr(gen, inst);
	}

	if(value->is_constant)
	{
		/* Determine the type of constant to be loaded */
		switch(jit_type_normalize(value->type)->kind)
		{
			case JIT_TYPE_SBYTE:
			case JIT_TYPE_UBYTE:
			case JIT_TYPE_SHORT:
			case JIT_TYPE_USHORT:

libjit/jit/jit-rules-arm.c  view on Meta::CPAN

				mov_reg_imm(gen, &inst, _jit_reg_info[reg].cpu_reg,
							(jit_nint)(value->address));
			}
			break;

			case JIT_TYPE_LONG:
			case JIT_TYPE_ULONG:
			{
				jit_long long_value;
				long_value = jit_value_get_long_constant(value);
				mov_reg_imm(gen, &inst, _jit_reg_info[reg].cpu_reg,
						    (jit_int)long_value);
				mov_reg_imm(gen, &inst, _jit_reg_info[reg].cpu_reg + 1,
						    (jit_int)(long_value >> 32));
			}
			break;

			case JIT_TYPE_FLOAT32:
			{
				jit_float32 float32_value;
				float32_value = jit_value_get_float32_constant(value);
				if(IS_WORD_REG(reg))
				{
					mov_reg_imm(gen, &inst, _jit_reg_info[reg].cpu_reg,
							    *((int *)&float32_value));
				}
				else
				{
					mov_freg_imm_32
						(gen, &inst, _jit_reg_info[reg].cpu_reg,
					     *((int *)&float32_value));
				}
			}
			break;

			case JIT_TYPE_FLOAT64:
			case JIT_TYPE_NFLOAT:
			{
				jit_float64 float64_value;
				float64_value = jit_value_get_float64_constant(value);
				if(IS_WORD_REG(reg))
				{
					mov_reg_imm
						(gen, &inst, _jit_reg_info[reg].cpu_reg,
						 ((int *)&float64_value)[0]);
					mov_reg_imm
						(gen, &inst, _jit_reg_info[reg].cpu_reg + 1,
						 ((int *)&float64_value)[1]);
				}
				else
				{
					mov_freg_imm_64
						(gen, &inst, _jit_reg_info[reg].cpu_reg,
					     ((int *)&float64_value)[0],
					     ((int *)&float64_value)[1]);
				}
			}
			break;
		}
	}
	else if(value->in_global_register)
	{
		/* Load the value out of a global register */
		if(IS_FLOAT_REG(reg))
		{
			/* Load into a floating point register */
#ifdef JIT_ARM_HAS_VFP
			/* Vector Floating Point instructions */
			if(jit_type_normalize(value->type)->kind == JIT_TYPE_FLOAT32)
			{
				arm_mov_float_reg(inst,
						  _jit_reg_info[reg].cpu_reg,
						  _jit_reg_info[value->global_reg].cpu_reg);
			}
			else
			{
				//JIT_TYPE_FLOAT64 or JIT_TYPE_NFLOAT
				arm_mov_double_reg_reg(inst,
						       _jit_reg_info[reg].cpu_reg,
						       _jit_reg_info[value->global_reg].cpu_reg,
						       _jit_reg_info[value->global_reg].cpu_reg + 1);
			}
#endif
#ifdef JIT_ARM_HAS_FPA
			/* Floating Point Architecture instructions */
			TODO();
			abort();
#endif
		}
		else
		{
			/* Load into a general-purpose register */
			arm_mov_reg_reg(inst,
					_jit_reg_info[reg].cpu_reg,
					_jit_reg_info[value->global_reg].cpu_reg);
		}
	}
	else if(value->in_register)
	{
		/* The value is already in another register. Move it */
		switch(jit_type_normalize(value->type)->kind)
		{
			case JIT_TYPE_SBYTE:
			case JIT_TYPE_UBYTE:
			case JIT_TYPE_SHORT:
			case JIT_TYPE_USHORT:
			case JIT_TYPE_INT:
			case JIT_TYPE_UINT:
			{
				arm_mov_reg_reg(inst, jit_reg_code(reg), jit_reg_code(value->reg));
			}
			break;

			case JIT_TYPE_LONG:
			case JIT_TYPE_ULONG:
			{
				assert(jit_reg_code(other_reg) !=-1);
				assert(jit_reg_other_reg(value->reg) != -1);
				
				arm_mov_reg_reg(inst, jit_reg_code(reg), jit_reg_code(value->reg));
				arm_mov_reg_reg(inst, jit_reg_code(other_reg), jit_reg_other_reg(value->reg));
			}
			break;

			case JIT_TYPE_FLOAT32:
			{
#ifdef JIT_ARM_HAS_VFP
				/* Vector Floating Point instructions */
				if(IS_FLOAT_REG(reg))
				{
					if(IS_WORD_REG(value->reg))
					{
						arm_mov_float_reg(inst,
								   jit_reg_code(reg),
								   jit_reg_code(value->reg));
					}
					else
					{
						arm_alu_freg_32(inst, ARM_MVF, 
								 jit_reg_code(reg),
								 jit_reg_code(value->reg));
					}
				}
				else
				{
					if(IS_WORD_REG(value->reg))
					{
						arm_mov_reg_reg(inst,
								 jit_reg_code(reg),
								 jit_reg_code(value->reg));
					}
					else
					{
						arm_mov_reg_float(inst,
								   jit_reg_code(reg),

libjit/jit/jit-rules-arm.c  view on Meta::CPAN

				/* Floating Point Architecture instructions */
				TODO();
				abort();
#endif
			}
			break;
			
			case JIT_TYPE_FLOAT64:
			case JIT_TYPE_NFLOAT:
			{
#ifdef JIT_ARM_HAS_VFP
				/* Vector Floating Point instruction */
				if(IS_FLOAT_REG(reg))
				{
					if(IS_WORD_REG(value->reg))
					{
						assert(jit_reg_other_reg(value->reg) != -1);
						
						arm_mov_double_reg_reg(inst,
									jit_reg_code(reg),
									jit_reg_code(value->reg),
									jit_reg_other_reg(value->reg));
					}
					else
					{
						arm_alu_freg(inst, ARM_MVF,
							      jit_reg_code(reg),
							      jit_reg_code(value->reg));
					}
				}
				else
				{
					if(IS_WORD_REG(value->reg))
					{
						arm_mov_reg_reg(inst,
								 jit_reg_code(reg),
								 jit_reg_code(value->reg));
					}
					else
					{
						assert(jit_reg_other_reg(reg));
						arm_mov_reg_reg_double(inst,
									jit_reg_code(reg),
									jit_reg_other_reg(reg),
									jit_reg_code(value->reg));
					}
				}
#endif
#ifdef JIT_ARM_HAS_FPA
				/* Floating Point Architecture instructions */
				TODO();
				abort();
#endif
			}
			break;
		}
	}
	else
	{
		/* Load from the stack */
		assert(!value->in_global_register && !value->is_constant && !value->in_register);
		
		/* Fix the position of the value in the stack frame */
		_jit_gen_fix_value(value);
		offset = (int)(value->frame_offset);

		switch(jit_type_normalize(value->type)->kind)
		{
			case JIT_TYPE_SBYTE:
			{
				arm_load_membase_sbyte(inst, _jit_reg_info[reg].cpu_reg,
								ARM_FP, offset);
			}
			break;

			case JIT_TYPE_UBYTE:
			{
				arm_load_membase_byte(inst, _jit_reg_info[reg].cpu_reg,
								ARM_FP, offset);
			}
			break;

			case JIT_TYPE_SHORT:
			{
				arm_load_membase_short(inst, _jit_reg_info[reg].cpu_reg,
								ARM_FP, offset);
			}
			break;

			case JIT_TYPE_USHORT:
			{
				arm_load_membase_ushort(inst, _jit_reg_info[reg].cpu_reg,
									ARM_FP, offset);
			}
			break;

			case JIT_TYPE_INT:
			case JIT_TYPE_UINT:
			{
				arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
								ARM_FP, offset);
			}
			break;

			case JIT_TYPE_LONG:
			case JIT_TYPE_ULONG:
			{
				arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
								ARM_FP, offset);
				arm_load_membase(inst, _jit_reg_info[reg].cpu_reg + 1,
								ARM_FP, offset + 4);
			}
			break;

			case JIT_TYPE_FLOAT32:
			{
				if(IS_WORD_REG(reg))
				{
					arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
									ARM_FP, offset);
				}
				else
				{
					arm_load_membase_float32
						(inst, _jit_reg_info[reg].cpu_reg, ARM_FP, offset);
				}
			}
			break;

			case JIT_TYPE_FLOAT64:
			case JIT_TYPE_NFLOAT:
			{
				if(IS_WORD_REG(reg))
				{
					arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
									ARM_FP, offset);
					arm_load_membase(inst, _jit_reg_info[reg].cpu_reg + 1,
									ARM_FP, offset + 4);
				}
				else
				{
					arm_load_membase_float64
						(inst, _jit_reg_info[reg].cpu_reg, ARM_FP, offset);
				}
			}
			break;
		}
	}

	/* End the code output process */
	jit_cache_end_output();
}

/**
 * Loads a struct indicated by "value" into the given register reg
 */
void _jit_gen_load_value_struct (jit_gencode_t gen, int reg, jit_value_t value)
{
	int offset;

	/* Make sure that we have sufficient space */
	jit_cache_setup_output(32);
	if(flush_if_too_far(gen))
	{
		jit_gen_load_inst_ptr(gen, inst);
	}

	if(value->is_constant)
	{
		TODO();
		abort();
	}
	else if(value->has_global_register)
	{
		/*
		 * This value has been assinged a global register. This means
		 * that it can use that register, but not necessarily that it's
		 * already in it!!
		 */
		
		/* Ensure that the value is already in the global_register */
		if (!value->in_global_register)
		{	
			/* Find the other register in a long pair */
			int reg = value->reg;
			int other_reg = jit_reg_current_other_reg(gen,reg);
			
			//Spill to the global register
			_jit_gen_spill_reg(gen, reg, other_reg, value);
			value->in_global_register=1;

			/* A new instruction has probably been generated by _jit_gen_spill_reg: reload the inst pointer */
			jit_gen_load_inst_ptr(gen, inst);
		}
		/* Load the value out of a global register */
		arm_mov_reg_reg(inst, _jit_reg_info[reg].cpu_reg,
						_jit_reg_info[value->global_reg].cpu_reg);
	}
	else
	{
		/* Fix the position of the value in the stack frame */
		_jit_gen_fix_value(value);
		offset = (int)(value->frame_offset);

		/* Ensure that the value is already in the stack frame */
		if(value->in_register)
		{
			/* Find the other register in a long pair */
			int reg = value->reg;
			int other_reg = jit_reg_current_other_reg(gen,reg);
			
			_jit_gen_spill_reg(gen, reg, other_reg, value);
			value->in_frame=1;

			/* A new instruction has probably been generated by _jit_gen_spill_reg: reload the inst pointer */
			jit_gen_load_inst_ptr(gen, inst);
		}
		
		assert(jit_type_normalize(value->type)->kind==JIT_TYPE_STRUCT);
		
		arm_load_membase(inst, _jit_reg_info[reg].cpu_reg, ARM_FP, offset);
		if (jit_type_get_size(jit_value_get_type(value)) > 4)
		{
			TODO();
			abort();
		}
		
	}

	/* End the code output process */
	jit_cache_end_output();
}

void _jit_gen_spill_global(jit_gencode_t gen, int reg, jit_value_t value)
{
	/* TODO: Implement if ARM needs it. */
}

void _jit_gen_load_global(jit_gencode_t gen, int reg, jit_value_t value)
{
	jit_cache_setup_output(32);
	arm_load_membase(inst, _jit_reg_info[value->global_reg].cpu_reg,
					 ARM_FP, value->frame_offset);
	jit_cache_end_output();
}

void _jit_gen_fix_value(jit_value_t value)
{
	if(!(value->has_frame_offset) && !(value->is_constant))
	{
		jit_nint size = (jit_nint)(ROUND_STACK(jit_type_get_size(value->type)));
		value->block->func->builder->frame_size += size;
		value->frame_offset = -(value->block->func->builder->frame_size);
		value->has_frame_offset = 1;
	}
}

void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
				   jit_block_t block, jit_insn_t insn)
{
	flush_if_too_far(gen);
	switch(insn->opcode)
	{
		#define JIT_INCLUDE_RULES
		#include "jit-rules-arm.inc"
		#undef JIT_INCLUDE_RULES

		default:
		{
			fprintf(stderr, "TODO(%x) at %s, %d\n",
					(int)(insn->opcode), __FILE__, (int)__LINE__);
		}
		break;
	}
}

void _jit_gen_start_block(jit_gencode_t gen, jit_block_t block)
{
	void **fixup;
	void **next;
	jit_nint offset;
	arm_inst_buf inst;

	/* Set the address of this block */
	block->address = (void *)(gen->ptr);

	/* If this block has pending fixups, then apply them now */
	fixup = (void **)(block->fixup_list);
	while(fixup != 0)
	{
		offset = (((jit_nint)(fixup[0])) & 0x00FFFFFF) << 2;
		if(!offset)
		{
			next = 0;
		}
		else
		{
			next = (void **)(((unsigned char *)fixup) - offset);
		}
		jit_gen_load_inst_ptr(gen, inst);
		arm_patch(inst, fixup, block->address);
		fixup = next;
	}
	block->fixup_list = 0;
}

void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
{
	/* Nothing to do here for ARM */
}

int _jit_gen_is_global_candidate(jit_type_t type)
{
	switch(jit_type_remove_tags(type)->kind)
	{
		case JIT_TYPE_INT:
		case JIT_TYPE_UINT:
		case JIT_TYPE_NINT:
		case JIT_TYPE_NUINT:
		case JIT_TYPE_PTR:
		case JIT_TYPE_SIGNATURE:	return 1;
	}
	return 0;
}

int
_jit_reg_get_pair(jit_type_t type, int reg)
{
	type = jit_type_normalize(type);
	if(type)
	{
		if(type->kind == JIT_TYPE_LONG || type->kind == JIT_TYPE_ULONG)
		{
			return jit_reg_other_reg(reg);
		}
		else if(type->kind == JIT_TYPE_FLOAT64 || type->kind == JIT_TYPE_NFLOAT)
		{
			if(reg == ARM_REG_R0)
			{
				return jit_reg_other_reg(reg);
			}
		}
	}
	return -1;
}

#endif /* JIT_BACKEND_ARM */



( run in 0.353 second using v1.01-cache-2.11-cpan-f0fbb3f571b )