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 )