info->abi_version = 0;
}
+/*
+ * Flush the contents of the constant pool.
+ */
+#define check_for_word() \
+ do { \
+ if(inst >= limit) \
+ { \
+ jit_cache_mark_full(&(gen->posn)); \
+ gen->num_constants = 0; \
+ gen->align_constants = 0; \
+ gen->first_constant_use = 0; \
+ return; \
+ } \
+ } while (0)
+static void flush_constants(jit_gencode_t gen, int after_epilog)
+{
+ arm_inst_ptr inst;
+ arm_inst_ptr limit;
+ arm_inst_ptr patch;
+ arm_inst_ptr current;
+ arm_inst_ptr fixup;
+ int index, value, offset;
+
+ /* Bail out if there are no constants to flush */
+ if(!(gen->num_constants))
+ {
+ return;
+ }
+
+ /* Initialize the cache output pointer */
+ inst = (arm_inst_ptr)(gen->posn.ptr);
+ limit = (arm_inst_ptr)(gen->posn.limit);
+
+ /* Jump over the constant pool if it is being output inline */
+ if(!after_epilog)
+ {
+ patch = inst;
+ check_for_word();
+ arm_jump_imm(inst, 0);
+ }
+ else
+ {
+ patch = 0;
+ }
+
+ /* Align the constant pool, if requested */
+ if(gen->align_constants && (((int)inst) & 7) != 0)
+ {
+ check_for_word();
+ *inst++ = 0;
+ }
+
+ /* Output the constant values and apply the necessary fixups */
+ for(index = 0; index < gen->num_constants; ++index)
+ {
+ current = inst;
+ check_for_word();
+ *inst++ = gen->constants[index];
+ fixup = gen->fixup_constants[index];
+ while(fixup != 0)
+ {
+ if((*fixup & 0x0F000000) == 0x05000000)
+ {
+ /* Word constant fixup */
+ value = *fixup & 0x0FFF;
+ offset = ((inst - 1 - fixup) * 4) - 8;
+ *fixup = ((*fixup & ~0x0FFF) | offset);
+ }
+ else
+ {
+ /* Floating-point constant fixup */
+ value = (*fixup & 0x00FF) * 4;
+ offset = ((inst - 1 - fixup) * 4) - 8;
+ *fixup = ((*fixup & ~0x00FF) | (offset / 4));
+ }
+ if(value)
+ {
+ fixup -= value;
+ }
+ else
+ {
+ fixup = 0;
+ }
+ }
+ }
+
+ /* Backpatch the jump if necessary */
+ if(!after_epilog)
+ {
+ arm_patch(patch, inst);
+ }
+
+ /* Flush the pool state and restart */
+ gen->num_constants = 0;
+ gen->align_constants = 0;
+ gen->first_constant_use = 0;
+}
+
+/*
+ * Perform a constant pool flush if we are too far from the starting point.
+ */
+static int flush_if_too_far(jit_gencode_t gen)
+{
+ if(gen->first_constant_use &&
+ (((arm_inst_ptr)(gen->posn.ptr)) -
+ ((arm_inst_ptr)(gen->first_constant_use))) >= 100)
+ {
+ flush_constants(gen, 0);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/*
+ * Add a fixup for a particular constant pool entry.
+ */
+static void add_constant_fixup
+ (jit_gencode_t gen, int index, arm_inst_ptr fixup)
+{
+ arm_inst_ptr prev;
+ int value;
+ prev = gen->fixup_constants[index];
+ if(prev)
+ {
+ value = fixup - prev;
+ }
+ else
+ {
+ value = 0;
+ }
+ if((*fixup & 0x0F000000) == 0x05000000)
+ {
+ *fixup = ((*fixup & ~0x0FFF) | value);
+ }
+ else
+ {
+ *fixup = ((*fixup & ~0x00FF) | (value / 4));
+ }
+ gen->fixup_constants[index] = fixup;
+ if(!(gen->first_constant_use))
+ {
+ gen->first_constant_use = fixup;
+ }
+}
+
+/*
+ * Add an immediate value to the constant pool. The constant
+ * is loaded from the instruction at "fixup".
+ */
+static void add_constant(jit_gencode_t gen, int value, arm_inst_ptr fixup)
+{
+ int index;
+
+ /* Search the constant pool for an existing copy of the value */
+ for(index = 0; index < gen->num_constants; ++index)
+ {
+ if(gen->constants[index] == value)
+ {
+ add_constant_fixup(gen, index, fixup);
+ return;
+ }
+ }
+
+ /* Flush the constant pool if there is insufficient space */
+ if(gen->num_constants >= JIT_ARM_MAX_CONSTANTS)
+ {
+ flush_constants(gen, 0);
+ }
+
+ /* Add the constant value to the pool */
+ gen->constants[gen->num_constants] = value;
+ gen->fixup_constants[gen->num_constants] = 0;
+ ++(gen->num_constants);
+ add_constant_fixup(gen, gen->num_constants - 1, fixup);
+}
+
+/*
+ * Add a double-word immedite value to the constant pool.
+ */
+static void add_constant_dword
+ (jit_gencode_t gen, int value1, int value2, arm_inst_ptr fixup, int align)
+{
+ int index;
+
+ /* Make sure that the constant pool is properly aligned when output */
+ if(align)
+ {
+ gen->align_constants = 1;
+ }
+
+ /* Search the constant pool for an existing copy of the value */
+ for(index = 0; index < (gen->num_constants - 1); ++index)
+ {
+ if(gen->constants[index] == value1 &&
+ gen->constants[index + 1] == value2)
+ {
+ if(!align || (index % 2) == 0)
+ {
+ add_constant_fixup(gen, index, fixup);
+ return;
+ }
+ }
+ }
+
+ /* Flush the constant pool if there is insufficient space */
+ if(gen->num_constants >= (JIT_ARM_MAX_CONSTANTS - 1))
+ {
+ flush_constants(gen, 0);
+ }
+
+ /* Align the constant pool on a 64-bit boundary if necessary */
+ if(align && (gen->num_constants % 2) != 0)
+ {
+ gen->constants[gen->num_constants] = 0;
+ gen->fixup_constants[gen->num_constants] = 0;
+ ++(gen->num_constants);
+ }
+
+ /* Add the double word constant value to the pool */
+ gen->constants[gen->num_constants] = value1;
+ gen->fixup_constants[gen->num_constants] = 0;
+ gen->constants[gen->num_constants] = value2;
+ gen->fixup_constants[gen->num_constants] = 0;
+ gen->num_constants += 2;
+ add_constant_fixup(gen, gen->num_constants - 2, fixup);
+}
+
+/*
+ * Load an immediate value into a word register. If the value is
+ * complicated, then add an entry to the constant pool.
+ */
+static arm_inst_ptr mov_reg_imm
+ (jit_gencode_t gen, arm_inst_ptr inst, int reg, int value)
+{
+ arm_inst_ptr fixup;
+
+ /* Bail out if the buffer is full */
+ if(inst >= (arm_inst_ptr)(gen->posn.limit))
+ {
+ return inst;
+ }
+
+ /* Bail out if the value is not complex enough to need a pool entry */
+ if(!arm_is_complex_imm(value))
+ {
+ arm_mov_reg_imm(inst, reg, value);
+ return inst;
+ }
+
+ /* Output a placeholder to load the value later */
+ fixup = inst;
+ arm_load_membase(inst, reg, ARM_PC, 0);
+
+ /* Add the constant to the pool, which may cause a flush */
+ gen->posn.ptr = (unsigned char *)inst;
+ add_constant(gen, value, fixup);
+
+ /* Return the new program counter location */
+ return (arm_inst_ptr)(gen->posn.ptr);
+}
+
+/*
+ * Load a float32 immediate value into a float register. If the value is
+ * complicated, then add an entry to the constant pool.
+ */
+static arm_inst_ptr mov_freg_imm_32
+ (jit_gencode_t gen, arm_inst_ptr inst, int reg, int value)
+{
+ arm_inst_ptr fixup;
+
+ /* Bail out if the buffer is full */
+ if(inst >= (arm_inst_ptr)(gen->posn.limit))
+ {
+ return inst;
+ }
+
+ /* Output a placeholder to load the value later */
+ fixup = inst;
+ arm_load_membase_float32(inst, reg, ARM_PC, 0);
+
+ /* Add the constant to the pool, which may cause a flush */
+ gen->posn.ptr = (unsigned char *)inst;
+ add_constant(gen, value, fixup);
+
+ /* Return the new program counter location */
+ return (arm_inst_ptr)(gen->posn.ptr);
+}
+
+/*
+ * Load a float64 immediate value into a float register. If the value is
+ * complicated, then add an entry to the constant pool.
+ */
+static arm_inst_ptr mov_freg_imm_64
+ (jit_gencode_t gen, arm_inst_ptr inst, int reg, int value1, int value2)
+{
+ arm_inst_ptr fixup;
+
+ /* Bail out if the buffer is full */
+ if(inst >= (arm_inst_ptr)(gen->posn.limit))
+ {
+ return inst;
+ }
+
+ /* Output a placeholder to load the value later */
+ fixup = inst;
+ arm_load_membase_float64(inst, reg, ARM_PC, 0);
+
+ /* Add the constant to the pool, which may cause a flush */
+ gen->posn.ptr = (unsigned char *)inst;
+ add_constant_dword(gen, value1, value2, fixup, 1);
+
+ /* Return the new program counter location */
+ return (arm_inst_ptr)(gen->posn.ptr);
+}
+
/*
* Force values out of parameter registers that cannot be easily
* accessed in register form (i.e. long, float, and struct values).
inst = (arm_inst_ptr)(gen->posn.ptr);
arm_pop_frame(inst, regset);
gen->posn.ptr = (unsigned char *)inst;
+
+ /* Flush the remainder of the constant pool */
+ flush_constants(gen, 1);
}
void *_jit_gen_redirector(jit_gencode_t gen, jit_function_t func)
int offset;
/* Make sure that we have sufficient space */
- jit_cache_setup_output(20);
+ jit_cache_setup_output(32);
+ if(flush_if_too_far(gen))
+ {
+ inst = (arm_inst_ptr)(gen->posn.ptr);
+ }
/* Output an appropriate instruction to spill the value */
if(value->has_global_register)
int offset;
/* Make sure that we have sufficient space */
- jit_cache_setup_output(16);
+ jit_cache_setup_output(32);
+ if(flush_if_too_far(gen))
+ {
+ inst = (arm_inst_ptr)(gen->posn.ptr);
+ }
if(value->is_constant)
{
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
{
- arm_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg,
- (jit_nint)(value->address));
+ inst = mov_reg_imm(gen, inst, _jit_reg_info[reg].cpu_reg,
+ (jit_nint)(value->address));
}
break;
{
jit_long long_value;
long_value = jit_value_get_long_constant(value);
- arm_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg,
- (jit_int)long_value);
- arm_mov_reg_imm(inst, _jit_reg_info[other_reg].cpu_reg,
- (jit_int)(long_value >> 32));
+ inst = mov_reg_imm(gen, inst, _jit_reg_info[reg].cpu_reg,
+ (jit_int)long_value);
+ inst = mov_reg_imm(gen, inst, _jit_reg_info[other_reg].cpu_reg,
+ (jit_int)(long_value >> 32));
}
break;
}
if(reg < 16)
{
- arm_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg,
- *((int *)&float32_value));
+ inst = mov_reg_imm(gen, inst, _jit_reg_info[reg].cpu_reg,
+ *((int *)&float32_value));
}
else
{
- arm_load_membase_float32
- (inst, _jit_reg_info[reg].cpu_reg, ARM_PC, 0);
- arm_jump_imm(inst, 0);
- *(inst)++ = *((int *)&float32_value);
+ inst = mov_freg_imm_32
+ (gen, inst, _jit_reg_info[reg].cpu_reg,
+ *((int *)&float32_value));
}
}
break;
}
if(reg < 16)
{
- arm_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg,
- ((int *)&float64_value)[0]);
- arm_mov_reg_imm(inst, _jit_reg_info[other_reg].cpu_reg,
- ((int *)&float64_value)[1]);
- }
- else if((((int)inst) & 7) == 0)
- {
- arm_load_membase_float64
- (inst, _jit_reg_info[reg].cpu_reg, ARM_PC, 0);
- arm_jump_imm(inst, 4);
- *(inst)++ = ((int *)&float64_value)[0];
- *(inst)++ = ((int *)&float64_value)[1];
+ inst = mov_reg_imm
+ (gen, inst, _jit_reg_info[reg].cpu_reg,
+ ((int *)&float64_value)[0]);
+ inst = mov_reg_imm
+ (gen, inst, _jit_reg_info[other_reg].cpu_reg,
+ ((int *)&float64_value)[1]);
}
else
{
- arm_load_membase_float64
- (inst, _jit_reg_info[reg].cpu_reg, ARM_PC, 4);
- arm_jump_imm(inst, 8);
- *(inst)++ = 0;
- *(inst)++ = ((int *)&float64_value)[0];
- *(inst)++ = ((int *)&float64_value)[1];
+ inst = mov_freg_imm_64
+ (gen, inst, _jit_reg_info[reg].cpu_reg,
+ ((int *)&float64_value)[0],
+ ((int *)&float64_value)[1]);
}
}
break;
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
{
case 0:
{
- arm_mov_reg_imm(inst, $1, 0);
+ arm_mov_reg_imm8(inst, $1, 0);
}
break;
[] -> {
if(jit_value_is_constant(insn->value1))
{
- arm_mov_reg_imm(inst, ARM_R0,
- ((jit_int *)(insn->value1->address))[0]);
- arm_mov_reg_imm(inst, ARM_R1,
- ((jit_int *)(insn->value1->address))[1]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_R0, ((jit_int *)(insn->value1->address))[0]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_R1, ((jit_int *)(insn->value1->address))[1]);
}
else
{
}
if(insn->value1->is_constant)
{
- arm_mov_reg_imm(inst, ARM_R0, ((int *)(insn->value1->address))[0]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_R0, ((int *)(insn->value1->address))[0]);
}
else
{
}
if(insn->value1->is_constant)
{
- arm_mov_reg_imm(inst, ARM_R0, ((int *)(insn->value1->address))[0]);
- arm_mov_reg_imm(inst, ARM_R1, ((int *)(insn->value1->address))[1]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_R0, ((int *)(insn->value1->address))[0]);
+ inst= mov_reg_imm
+ (gen, inst, ARM_R1, ((int *)(insn->value1->address))[1]);
}
else
{
}
if(insn->value1->is_constant)
{
- arm_mov_reg_imm(inst, ARM_WORK,
- ((int *)(insn->value1->address))[0]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
arm_store_membase(inst, ARM_WORK, ARM_FP,
insn->dest->frame_offset);
- arm_mov_reg_imm(inst, ARM_WORK,
- ((int *)(insn->value1->address))[1]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
arm_store_membase(inst, ARM_WORK, ARM_FP,
insn->dest->frame_offset + 4);
}
}
if(insn->value1->is_constant)
{
- arm_mov_reg_imm(inst, ARM_WORK,
- ((int *)(insn->value1->address))[0]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
}
else
{
}
if(insn->value1->is_constant)
{
- arm_mov_reg_imm(inst, ARM_WORK,
- ((int *)(insn->value1->address))[0]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
arm_store_membase(inst, ARM_WORK, ARM_FP,
insn->dest->frame_offset);
- arm_mov_reg_imm(inst, ARM_WORK,
- ((int *)(insn->value1->address))[1]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
arm_store_membase(inst, ARM_WORK, ARM_FP,
insn->dest->frame_offset + 4);
}
}
if(insn->value1->is_constant)
{
- arm_mov_reg_imm(inst, ARM_WORK,
- ((int *)(insn->value1->address))[1]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
arm_push_reg(inst, ARM_WORK);
- arm_mov_reg_imm(inst, ARM_WORK,
- ((int *)(insn->value1->address))[0]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
arm_push_reg(inst, ARM_WORK);
}
else
}
if(insn->value1->is_constant)
{
- arm_mov_reg_imm(inst, ARM_WORK,
- ((int *)(insn->value1->address))[0]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
}
else
{
}
if(insn->value1->is_constant)
{
- arm_mov_reg_imm(inst, ARM_WORK,
- ((int *)(insn->value1->address))[1]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
arm_push_reg(inst, ARM_WORK);
- arm_mov_reg_imm(inst, ARM_WORK,
- ((int *)(insn->value1->address))[0]);
+ inst = mov_reg_imm
+ (gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
arm_push_reg(inst, ARM_WORK);
}
else