}
/*@
- * @deftypefun void _jit_regs_want_reg (jit_gencode_t gen, int reg)
+ * @deftypefun void _jit_regs_want_reg (jit_gencode_t gen, int reg, int for_long)
* Tell the register allocator that we want a particular register
* for a specific purpose. The current contents of the register
* are spilled. If @code{reg} is part of a register pair, then the
}
}
-/*@
- * @deftypefun int _jit_regs_load_value (jit_gencode_t gen, jit_value_t value, int destroy, int used_again)
- * Load a value into any register that is suitable and return that register.
- * If the value needs a long pair, then this will return the first register
- * in the pair. Returns -1 if the value will not fit into any register.
- *
- * If @code{destroy} is non-zero, then we are about to destroy the register,
- * so the system must make sure that such destruction will not side-effect
- * @code{value} or any of the other values currently in that register.
- *
- * If @code{used_again} is non-zero, then it indicates that the value is
- * used again further down the block.
- * @end deftypefun
-@*/
-int _jit_regs_load_value
- (jit_gencode_t gen, jit_value_t value, int destroy, int used_again)
+/*
+ * Find a free register to hold the contents of a value.
+ */
+static int free_register_for_value
+ (jit_gencode_t gen, jit_value_t value, int *other_reg)
{
- int reg, other_reg, type;
+ int reg, type;
int suitable_reg, need_pair;
int suitable_age;
+ /* Clear the other register before we start */
+ *other_reg = -1;
+
/* Determine if we need a long pair for this value */
need_pair = _jit_regs_needs_long_pair(value->type);
- /* If the value is already in a register, then try to use that register */
- if(value->in_register)
- {
- reg = value->reg;
- if(destroy)
- {
- if(gen->contents[reg].num_values == 1 &&
- (value->in_frame || !used_again))
- {
- /* We are the only value in this register, and the
- value is duplicated in the frame, or will never
- be used again in this block. In this case,
- we can disassociate the register from the value
- and just return the register as-is */
- value->in_register = 0;
- gen->contents[reg].num_values = 0;
- gen->contents[reg].used_for_temp = 1;
- gen->contents[reg].age = gen->current_age;
- if(need_pair)
- {
- other_reg = _jit_reg_info[reg].other_reg;
- gen->contents[other_reg].used_for_temp = 1;
- gen->contents[other_reg].age = gen->current_age;
- }
- ++(gen->current_age);
- return reg;
- }
- else
- {
- /* We need to spill the register and then reload it */
- spill_register(gen, reg);
- }
- }
- else
- {
- gen->contents[reg].age = gen->current_age;
- if(need_pair)
- {
- other_reg = _jit_reg_info[reg].other_reg;
- gen->contents[other_reg].age = gen->current_age;
- }
- ++(gen->current_age);
- return reg;
- }
- }
-
/* Determine the type of register that we need */
switch(jit_type_normalize(value->type)->kind)
{
{
/* We always load stack values to the top of the stack */
reg = create_stack_reg(gen, reg, 1);
- load_value(gen, reg, -1, value, destroy);
return reg;
}
else if(!need_pair)
if(gen->contents[reg].num_values == 0 &&
!(gen->contents[reg].used_for_temp))
{
- load_value(gen, reg, -1, value, destroy);
return reg;
}
}
else
{
- other_reg = _jit_reg_info[reg].other_reg;
+ *other_reg = _jit_reg_info[reg].other_reg;
if(gen->contents[reg].num_values == 0 &&
!(gen->contents[reg].used_for_temp) &&
- gen->contents[other_reg].num_values == 0 &&
- !(gen->contents[other_reg].used_for_temp))
+ gen->contents[*other_reg].num_values == 0 &&
+ !(gen->contents[*other_reg].used_for_temp))
{
- load_value(gen, reg, other_reg, value, destroy);
return reg;
}
}
}
/* Eject the current contents of the register */
- reg = _jit_regs_want_reg(gen, reg, need_pair);
+ reg = _jit_regs_want_reg(gen, suitable_reg, need_pair);
+ if(need_pair)
+ {
+ *other_reg = _jit_reg_info[reg].other_reg;
+ }
+ return reg;
+}
+
+/*@
+ * @deftypefun int _jit_regs_load_value (jit_gencode_t gen, jit_value_t value, int destroy, int used_again)
+ * Load a value into any register that is suitable and return that register.
+ * If the value needs a long pair, then this will return the first register
+ * in the pair. Returns -1 if the value will not fit into any register.
+ *
+ * If @code{destroy} is non-zero, then we are about to destroy the register,
+ * so the system must make sure that such destruction will not side-effect
+ * @code{value} or any of the other values currently in that register.
+ *
+ * If @code{used_again} is non-zero, then it indicates that the value is
+ * used again further down the block.
+ * @end deftypefun
+@*/
+int _jit_regs_load_value
+ (jit_gencode_t gen, jit_value_t value, int destroy, int used_again)
+{
+ int reg, other_reg, need_pair;
- /* Load the value into the register */
- if(!need_pair)
+ /* Determine if we need a long pair for this value */
+ need_pair = _jit_regs_needs_long_pair(value->type);
+
+ /* If the value is already in a register, then try to use that register */
+ if(value->in_register)
{
- load_value(gen, reg, -1, value, destroy);
+ reg = value->reg;
+ if(destroy)
+ {
+ if(gen->contents[reg].num_values == 1 &&
+ (value->in_frame || !used_again))
+ {
+ /* We are the only value in this register, and the
+ value is duplicated in the frame, or will never
+ be used again in this block. In this case,
+ we can disassociate the register from the value
+ and just return the register as-is */
+ value->in_register = 0;
+ gen->contents[reg].num_values = 0;
+ gen->contents[reg].used_for_temp = 1;
+ gen->contents[reg].age = gen->current_age;
+ if(need_pair)
+ {
+ other_reg = _jit_reg_info[reg].other_reg;
+ gen->contents[other_reg].used_for_temp = 1;
+ gen->contents[other_reg].age = gen->current_age;
+ }
+ ++(gen->current_age);
+ return reg;
+ }
+ else
+ {
+ /* We need to spill the register and then reload it */
+ spill_register(gen, reg);
+ }
+ }
+ else
+ {
+ gen->contents[reg].age = gen->current_age;
+ if(need_pair)
+ {
+ other_reg = _jit_reg_info[reg].other_reg;
+ gen->contents[other_reg].age = gen->current_age;
+ }
+ ++(gen->current_age);
+ return reg;
+ }
}
- else
+
+ /* Search for a free register to hold the value */
+ reg = free_register_for_value(gen, value, &other_reg);
+ load_value(gen, reg, other_reg, value, destroy);
+ return reg;
+}
+
+/*@
+ * @deftypefun int _jit_regs_dest_value (jit_gencode_t gen, jit_value_t value)
+ * Get a new register to hold @code{value} as a destination. This cannot
+ * be used for stack register destinations (use @code{_jit_regs_new_top}
+ * for that).
+ * @end deftypefun
+@*/
+int _jit_regs_dest_value(jit_gencode_t gen, jit_value_t value)
+{
+ int reg, other_reg;
+
+ /* If the value is exclusively in a register already, then use that */
+ if(value->in_register)
{
- load_value(gen, reg, _jit_reg_info[reg].other_reg, value, destroy);
+ reg = value->reg;
+ if(gen->contents[reg].num_values == 1)
+ {
+ value->in_frame = 0;
+ return reg;
+ }
+ free_reg_and_spill(gen, reg, 0, 1);
}
+
+ /* Find a suitable register to hold the destination */
+ reg = free_register_for_value(gen, value, &other_reg);
+ _jit_regs_set_value(gen, reg, value, 0);
return reg;
}
/* Return the allocated register to the caller */
return reg;
}
+
+/*@
+ * @deftypefun void _jit_regs_force_out (jit_gencode_t gen, jit_value_t value, int is_dest)
+ * If @code{value} is currently in a register, then force its value out
+ * into the stack frame. The @code{is_dest} flag indicates that the value
+ * will be a destination, so we don't care about the original value.
+ * @end deftypefun
+@*/
+void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest)
+{
+ if(value->in_register)
+ {
+ if((_jit_reg_info[value->reg].flags & JIT_REG_IN_STACK) == 0)
+ {
+ free_reg_and_spill(gen, value->reg, 0, !is_dest);
+ }
+ else
+ {
+ /* Always do a spill for a stack register */
+ _jit_regs_want_reg(gen, value->reg, 0);
+ }
+ }
+}
[reg] -> {
/* TODO: won't work in a function with a "try" block */
unsigned char *patch;
+ TODO();
x86_alu_reg_reg(inst, X86_OR, $1, $1);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
JIT_OP_RETURN_SMALL_STRUCT: spill_before
[] -> {
/* TODO: load the structure value into EAX:EDX */
+ TODO();
inst = jump_to_epilog(gen, inst, block);
}
JIT_OP_IMPORT:
[] -> {
/* TODO */
+ TODO();
}
/*
JIT_OP_COPY_LONG: spill_before
[] -> {
/* TODO */
+ TODO();
}
JIT_OP_COPY_FLOAT32: unary
JIT_OP_COPY_NFLOAT: unary
[freg] -> {}
-JIT_OP_COPY_STRUCT:
+JIT_OP_COPY_STRUCT: manual
[] -> {
/* TODO */
+ TODO();
}
-JIT_OP_COPY_STORE_BYTE:
+JIT_OP_COPY_STORE_BYTE: manual
[] -> {
- /* TODO */
+ unsigned char *inst;
+ int reg;
+ _jit_regs_force_out(gen, insn->dest, 1);
+ _jit_gen_fix_value(insn->dest);
+ if(!(insn->value1->is_constant))
+ {
+ reg = _jit_regs_load_value
+ (gen, insn->value1, 0,
+ (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
+ JIT_INSN_VALUE1_LIVE)));
+ inst = gen->posn.ptr;
+ if(!jit_cache_check_for_n(&(gen->posn), 32))
+ {
+ jit_cache_mark_full(&(gen->posn));
+ return;
+ }
+ inst = mov_membase_reg_byte
+ (inst, X86_EBP, insn->dest->frame_offset,
+ _jit_reg_info[reg].cpu_reg);
+ gen->posn.ptr = inst;
+ }
+ else
+ {
+ inst = gen->posn.ptr;
+ if(!jit_cache_check_for_n(&(gen->posn), 32))
+ {
+ jit_cache_mark_full(&(gen->posn));
+ return;
+ }
+ x86_mov_membase_imm(inst, X86_EBP, insn->dest->frame_offset,
+ insn->value1->address, 1);
+ gen->posn.ptr = inst;
+ }
}
-JIT_OP_COPY_STORE_SHORT:
+JIT_OP_COPY_STORE_SHORT: manual
[] -> {
- /* TODO */
+ unsigned char *inst;
+ int reg;
+ _jit_regs_force_out(gen, insn->dest, 1);
+ _jit_gen_fix_value(insn->dest);
+ if(!(insn->value1->is_constant))
+ {
+ reg = _jit_regs_load_value
+ (gen, insn->value1, 0,
+ (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
+ JIT_INSN_VALUE1_LIVE)));
+ inst = gen->posn.ptr;
+ if(!jit_cache_check_for_n(&(gen->posn), 32))
+ {
+ jit_cache_mark_full(&(gen->posn));
+ return;
+ }
+ x86_mov_membase_reg(inst, X86_EBP, insn->dest->frame_offset,
+ _jit_reg_info[reg].cpu_reg, 2);
+ gen->posn.ptr = inst;
+ }
+ else
+ {
+ inst = gen->posn.ptr;
+ if(!jit_cache_check_for_n(&(gen->posn), 32))
+ {
+ jit_cache_mark_full(&(gen->posn));
+ return;
+ }
+ x86_mov_membase_imm(inst, X86_EBP, insn->dest->frame_offset,
+ insn->value1->address, 2);
+ gen->posn.ptr = inst;
+ }
}
-JIT_OP_ADDRESS_OF:
+JIT_OP_ADDRESS_OF: manual
[] -> {
+ unsigned char *inst;
+ int reg;
+ _jit_regs_force_out(gen, insn->value1, 0);
_jit_gen_fix_value(insn->value1);
- /* TODO: get a register to hold the result */
+ inst = gen->posn.ptr;
+ if(!jit_cache_check_for_n(&(gen->posn), 32))
+ {
+ jit_cache_mark_full(&(gen->posn));
+ return;
+ }
+ reg = _jit_regs_dest_value(gen, insn->dest);
+ reg = _jit_reg_info[reg].cpu_reg;
+ x86_lea_membase(inst, reg, X86_EBP, insn->value1->frame_offset);
+ gen->posn.ptr = inst;
}
/*
JIT_OP_PUSH_STRUCT: unary_note
[reg] -> {
/* TODO */
+ TODO();
}
JIT_OP_POP_STACK:
JIT_OP_LOAD_RELATIVE_STRUCT: manual
[] -> {
/* TODO */
+ TODO();
}
JIT_OP_STORE_RELATIVE_BYTE: manual
JIT_OP_STORE_RELATIVE_STRUCT: manual
[] -> {
/* TODO */
+ TODO();
}
JIT_OP_ADD_RELATIVE: unary