/* Value usage flags. */
#define VALUE_INPUT 1
-#define VALUE_OUTPUT 2
-#define VALUE_USED 4
+#define VALUE_USED 2
+#define VALUE_LIVE 4
+#define VALUE_DEAD 8
/* Clobber flags. */
#define CLOBBER_NONE 0
/*
* Check if the value is used in and after the current instruction.
+ *
+ * The value is dead if it is the output value of the instruction and hence
+ * just about to be recomputed or if it is one of the input values and its
+ * usage flags are not set. Otherwise the value is alive.
*/
static int
value_usage(_jit_regs_t *regs, jit_value_t value)
{
- int flags = 0;
+ int flags;
+
+ flags = 0;
+ if(value->is_constant)
+ {
+ flags |= VALUE_DEAD;
+ }
if(value == regs->descs[0].value)
{
- flags |= regs->ternary ? VALUE_INPUT : VALUE_OUTPUT;
- if(regs->descs[0].used || regs->descs[0].live)
+ if(regs->ternary)
+ {
+ flags |= VALUE_INPUT;
+ if(regs->descs[0].used)
+ {
+ flags |= VALUE_LIVE | VALUE_USED;
+ }
+ else if(regs->descs[0].live)
+ {
+ flags |= VALUE_LIVE;
+ }
+ else
+ {
+ flags |= VALUE_DEAD;
+ }
+ }
+ else
{
- flags |= VALUE_USED;
+ flags |= VALUE_DEAD;
}
}
if(value == regs->descs[1].value)
{
flags |= VALUE_INPUT;
- if(regs->descs[1].used || regs->descs[1].live)
+ if(regs->descs[1].used)
{
- flags |= VALUE_USED;
+ flags |= VALUE_LIVE | VALUE_USED;
+ }
+ else if(regs->descs[1].live)
+ {
+ flags |= VALUE_LIVE;
+ }
+ else
+ {
+ flags |= VALUE_DEAD;
}
}
if(value == regs->descs[2].value)
{
flags |= VALUE_INPUT;
- if(regs->descs[2].used || regs->descs[2].live)
+ if(regs->descs[2].used)
+ {
+ flags |= VALUE_LIVE | VALUE_USED;
+ }
+ else if(regs->descs[2].live)
+ {
+ flags |= VALUE_LIVE;
+ }
+ else
{
- flags |= VALUE_USED;
+ flags |= VALUE_DEAD;
}
}
return flags;
is_register_alive(jit_gencode_t gen, _jit_regs_t *regs, int reg)
{
int index, usage;
- jit_value_t value;
- if(reg < 0)
- {
- return 0;
- }
-
- for(index = 0; index < gen->contents[reg].num_values; index++)
+ if(reg >= 0)
{
- value = gen->contents[reg].values[index];
- if(value->is_constant)
- {
- continue;
- }
-
- /* The value is dead if it is the output value of the
- instruction and hence just about to be recomputed
- or if it is one of the input values and its usage
- flags are not set. Otherwise the value is alive. */
- usage = value_usage(regs, value);
- if((usage & VALUE_OUTPUT) == 0
- && ((usage & VALUE_INPUT) == 0
- || (usage & VALUE_USED) != 0))
+ for(index = 0; index < gen->contents[reg].num_values; index++)
{
- return 1;
+ usage = value_usage(regs, gen->contents[reg].values[index]);
+ if((usage & VALUE_DEAD) == 0)
+ {
+ return 1;
+ }
}
}
return 0;
desc->clobber = 0;
desc->early_clobber = 0;
desc->duplicate = 0;
+ desc->save = 0;
desc->load = 0;
desc->copy = 0;
+ desc->kill = 0;
}
/*
}
static int
-collect_register_info(_jit_regs_t *regs, int index)
+collect_register_info(jit_gencode_t gen, _jit_regs_t *regs, int index)
{
_jit_regdesc_t *desc;
+ int reg, other_reg;
int stack_start;
+#ifdef JIT_REG_DEBUG
+ printf("collect_register_info(index = %d)\n", index);
+#endif
+
desc = ®s->descs[index];
- if(desc->reg < 0)
- {
- return 1;
- }
- if(desc->duplicate)
+ if(desc->reg < 0 || desc->duplicate)
{
return 1;
}
}
}
+ if(index > 0 || regs->ternary)
+ {
+ if(desc->value->is_constant)
+ {
+ desc->kill = 1;
+ }
+ else if(desc->value->in_register)
+ {
+ reg = desc->value->reg;
+ if(gen->contents[reg].is_long_start)
+ {
+ other_reg = OTHER_REG(reg);
+ }
+ else
+ {
+ other_reg = -1;
+ }
+
+ if(desc->used)
+ {
+ if(jit_reg_is_used(regs->clobber, reg)
+ || (other_reg >= 0
+ && jit_reg_is_used(regs->clobber, other_reg)))
+ {
+ desc->save = 1;
+ desc->kill = 1;
+ }
+ }
+ else
+ {
+ if(desc->live)
+ {
+ desc->save = 1;
+ }
+ desc->kill = 1;
+ }
+ }
+ else if(desc->load)
+ {
+ if(desc->used)
+ {
+ if(jit_reg_is_used(regs->clobber, desc->reg)
+ || (desc->other_reg >= 0
+ && jit_reg_is_used(regs->clobber, desc->other_reg)))
+ {
+ desc->kill = 1;
+ }
+ }
+ else
+ {
+ desc->kill = 1;
+ }
+ }
+ }
+
if(IS_STACK_REG(desc->reg))
{
stack_start = get_stack_start(desc->reg);
}
}
+#ifdef JIT_REG_DEBUG
+ printf("value = ");
+ jit_dump_value(stdout, jit_value_get_function(desc->value), desc->value, 0);
+ printf("\n");
+ printf("reg = %d\n", desc->reg);
+ printf("other_reg = %d\n", desc->other_reg);
+ printf("live = %d\n", desc->live);
+ printf("used = %d\n", desc->used);
+ printf("clobber = %d\n", desc->clobber);
+ printf("early_clobber = %d\n", desc->early_clobber);
+ printf("duplicate = %d\n", desc->duplicate);
+ printf("save = %d\n", desc->save);
+ printf("load = %d\n", desc->load);
+ printf("copy = %d\n", desc->copy);
+ printf("kill = %d\n", desc->kill);
+#endif
+
return 1;
}
for(index = 0; index < gen->contents[reg].num_values; index++)
{
value = gen->contents[reg].values[index];
- if(value->is_constant)
- {
- continue;
- }
usage = value_usage(regs, value);
- if((usage & VALUE_OUTPUT) != 0)
+ if((usage & VALUE_DEAD) != 0)
{
+ /* the value is not spilled */
continue;
}
- if((usage & VALUE_INPUT) != 0 && (usage & VALUE_USED) == 0)
+ if((usage & VALUE_LIVE) != 0 && (usage & VALUE_USED) == 0)
{
+ /* the value has to be spilled anyway */
+ /* NOTE: This is true for local register allocation,
+ review for future global allocator. */
continue;
}
if(value->has_global_register)
for(index = 0; index < gen->contents[other_reg].num_values; index++)
{
value = gen->contents[other_reg].values[index];
- if(value->is_constant)
- {
- continue;
- }
usage = value_usage(regs, value);
- if((usage & VALUE_OUTPUT) != 0)
+ if((usage & VALUE_DEAD) != 0)
{
+ /* the value is not spilled */
continue;
}
- if((usage & VALUE_INPUT) != 0 && (usage & VALUE_USED) == 0)
+ if((usage & VALUE_LIVE) != 0 && (usage & VALUE_USED) == 0)
{
+ /* the value has to be spilled anyway */
+ /* NOTE: This is true for local register allocation,
+ review for future global allocator. */
continue;
}
if(value->has_global_register)
}
reg = suitable_reg;
- if(desc && reg >= 0)
+ if(reg >= 0)
{
- if(need_pair)
+ if(desc)
{
- other_reg = OTHER_REG(reg);
+ if(need_pair)
+ {
+ other_reg = OTHER_REG(reg);
+ }
+ else
+ {
+ other_reg = -1;
+ }
+ set_regdesc_register(gen, regs, index, reg, other_reg);
}
else
{
- other_reg = -1;
+ set_register_flags(gen, regs, reg, 1, 0);
}
- set_regdesc_register(gen, regs, index, reg, other_reg);
}
return reg;
return;
}
-static int
-adjust_register(_jit_regs_t *regs, int reg)
-{
- int index;
- if(reg > regs->initial_stack_top)
- {
- reg -= regs->initial_stack_top;
- reg += regs->current_stack_top;
- }
- else
- {
- for(index = 0; index < regs->num_exchanges; index++)
- {
- if(reg == regs->exchanges[index][0])
- {
- reg = regs->exchanges[index][1];
- }
- else if(reg == regs->exchanges[index][1])
- {
- reg = regs->exchanges[index][0];
- }
- }
- }
- return reg;
-}
-
static void
adjust_assignment(jit_gencode_t gen, _jit_regs_t *regs, int index)
{
else if(regs->wanted_stack_count == 2)
{
/* a binary op */
- if(regs->x87_arith)
+
+ /* find the input value the output goes to */
+ if(index == 0)
{
- desc->reg = adjust_register(regs, desc->reg);
+ index = 1 + (regs->reverse_dest ^ regs->reverse_args);
}
- else if(index == 0)
+
+ if(regs->x87_arith && desc->value->in_register && !desc->copy)
{
- desc->reg = regs->current_stack_top - regs->loaded_stack_count + 1;
+ desc->reg = desc->value->reg;
}
else
{
desc1 = ®s->descs[1];
desc2 = ®s->descs[2];
- if(desc1->value->in_register && desc2->value->in_register)
+ if(desc1->value->in_register && !desc1->copy
+ && desc2->value->in_register && !desc2->copy)
{
- /* TODO: simulate spills and find out if any of the input
- values ends up on the stack top. */
- /* TODO: otherwise see if the next instruction wants output
- or remaining input to be on the stack top. */
- top_index = 2;
+ /* Is any of the input values is on the stack top? */
+ if(desc1->value->reg == regs->current_stack_top)
+ {
+ top_index = 1;
+ }
+ else if(desc1->value->reg == regs->current_stack_top)
+ {
+ top_index = 2;
+ }
+ else
+ {
+ /* TODO: See if the next instruction wants output
+ or remaining input to be on the stack top. */
+ top_index = 2;
+ }
}
- else if(desc1->value->in_register)
+ else if(desc1->value->in_register && !desc1->copy)
{
top_index = 2;
}
- else if(desc2->value->in_register)
+ else if(desc2->value->in_register && !desc2->copy)
{
top_index = 1;
}
gen->contents[reg].remap = -1;
}
+/*
+ * Associate a temporary with register.
+ */
static void
bind_temporary(jit_gencode_t gen, int reg, int other_reg)
{
}
}
+/*
+ * Associate value with register.
+ */
static void
bind_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int still_in_frame)
{
static void
exch_stack_top(jit_gencode_t gen, int reg, int pop)
{
- int top, index;
+ int stack_start, top, index;
int num_values, used_for_temp, age;
jit_value_t value1, value2;
}
/* Find the top of the stack. */
- top = gen->stack_map[get_stack_start(reg)];
+ stack_start = get_stack_start(reg);
+ top = get_stack_top(gen, stack_start);
/* Generate exchange instruction. */
_jit_gen_exch_top(gen, reg, pop);
+ if(pop)
+ {
+ remap_stack_down(gen, stack_start, top);
+ }
/* Update information about the contents of the registers. */
for(index = 0;
index < gen->contents[reg].num_values || index < gen->contents[top].num_values;
index++)
{
- value1 = (index < gen->contents[reg].num_values
- ? gen->contents[reg].values[index] : 0);
- value2 = (index < gen->contents[top].num_values
+ value1 = (index < gen->contents[top].num_values
? gen->contents[top].values[index] : 0);
+ value2 = (index < gen->contents[reg].num_values
+ ? gen->contents[reg].values[index] : 0);
+
+ if(value1)
+ {
+ value1->reg = reg;
+ }
+ gen->contents[reg].values[index] = value1;
if(pop)
{
- if(value1)
+ if(value2)
{
- value1->reg = -1;
+ value2->reg = -1;
}
gen->contents[top].values[index] = 0;
}
else
{
- if(value1)
+ if(value2)
{
- value1->reg = top;
+ value2->reg = top;
}
- gen->contents[top].values[index] = value1;
- }
- if(value2)
- {
- value2->reg = reg;
+ gen->contents[top].values[index] = value2;
}
- gen->contents[reg].values[index] = value2;
}
- num_values = gen->contents[top].num_values;
- used_for_temp = gen->contents[top].used_for_temp;
- age = gen->contents[top].age;
if(pop)
{
- gen->contents[top].num_values = 0;
- gen->contents[top].used_for_temp = 0;
- gen->contents[top].age = 0;
+ num_values = 0;
+ used_for_temp = 0;
+ age = 0;
}
else
{
- gen->contents[top].num_values = gen->contents[reg].num_values;
- gen->contents[top].used_for_temp = gen->contents[reg].used_for_temp;
- gen->contents[top].age = gen->contents[reg].age;
+ num_values = gen->contents[reg].num_values;
+ used_for_temp = gen->contents[reg].used_for_temp;
+ age = gen->contents[reg].age;
}
- gen->contents[reg].num_values = num_values;
- gen->contents[reg].used_for_temp = used_for_temp;
- gen->contents[reg].age = age;
+ gen->contents[reg].num_values = gen->contents[top].num_values;
+ gen->contents[reg].used_for_temp = gen->contents[top].used_for_temp;
+ gen->contents[reg].age = gen->contents[top].age;
+ gen->contents[top].num_values = num_values;
+ gen->contents[top].used_for_temp = used_for_temp;
+ gen->contents[top].age = age;
}
/*
- * Spill the top of the register stack.
+ * Drop value from register.
*/
static void
-spill_stack_top(jit_gencode_t gen, _jit_regs_t *regs, int reg)
+free_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg)
{
- int stack_start, top, index;
- jit_value_t value;
- int usage, value_used;
-
#ifdef JIT_REG_DEBUG
- printf("spill_stack_top(reg = %d)\n", reg);
+ printf("free_value(value = ");
+ jit_dump_value(stdout, jit_value_get_function(value), value, 0);
+ printf(", reg = %d, other_reg = %d)\n", reg, other_reg);
#endif
- if(!IS_STACK_REG(reg))
+ /* Never free global registers. */
+ if(value->has_global_register)
{
return;
}
- stack_start = get_stack_start(reg);
- top = get_stack_top(gen, stack_start);
-
- value_used = 0;
- for(index = gen->contents[top].num_values - 1; index >= 0; --index)
+ /* Free stack register. */
+ if(IS_STACK_REG(reg) && gen->contents[reg].num_values == 1)
{
- value = gen->contents[top].values[index];
+ exch_stack_top(gen, reg, 1);
+ }
- usage = value_usage(regs, value);
- if((usage & VALUE_INPUT) != 0 && (usage & VALUE_USED) == 0)
+ unbind_value(gen, value, reg, other_reg);
+}
+
+/*
+ * Save the value from the register into its frame position and optionally free it.
+ * If the value is already in the frame or is a constant then it is not saved but
+ * the free option still applies to them.
+ */
+static void
+save_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int free)
+{
+ int stack_start, top;
+
+#ifdef JIT_REG_DEBUG
+ printf("save_value(value = ");
+ jit_dump_value(stdout, jit_value_get_function(value), value, 0);
+ printf(", reg = %d, other_reg = %d)\n", reg, other_reg);
+#endif
+ /* First take care of values that reside in global registers. */
+ if(value->has_global_register)
+ {
+ if(value->global_reg != reg && !value->in_global_register)
{
- continue;
+ _jit_gen_spill_reg(gen, reg, other_reg, value);
+ value->in_global_register = 1;
}
+ return;
+ }
- if(!(value->is_constant || value->in_frame || (usage & VALUE_OUTPUT) != 0))
+ /* Take care of constants and values that are already in frame. */
+ if(value->is_constant || value->in_frame)
+ {
+ if(free)
{
- if((usage & VALUE_INPUT) == 0 && gen->contents[top].num_values == 1)
- {
- value_used = 1;
- }
+ free_value(gen, value, reg, other_reg);
+ }
+ return;
+ }
- _jit_gen_spill_top(gen, top, value, value_used);
- value->in_frame = 1;
+ /* Now really save the value into frame. */
+ if(IS_STACK_REG(reg))
+ {
+ /* Find the top of the stack. */
+ stack_start = get_stack_start(reg);
+ top = get_stack_top(gen, stack_start);
+
+ /* Move the value on the stack top if it is already not there. */
+ if(top != reg)
+ {
+ exch_stack_top(gen, reg, 0);
}
- if((usage & VALUE_INPUT) == 0)
+ if(free && gen->contents[top].num_values == 1)
{
- if(gen->contents[top].num_values == 1)
- {
- _jit_gen_free_reg(gen, top, -1, value_used);
- remap_stack_down(gen, stack_start, top);
- }
- unbind_value(gen, value, top, -1);
+ _jit_gen_spill_top(gen, top, value, 1);
+ remap_stack_down(gen, stack_start, top);
+ }
+ else
+ {
+ _jit_gen_spill_top(gen, top, value, 0);
}
}
+ else
+ {
+ _jit_gen_spill_reg(gen, reg, other_reg, value);
+ }
+
+ if(free)
+ {
+ unbind_value(gen, value, reg, other_reg);
+ }
+ value->in_frame = 1;
}
/*
other_reg = -1;
}
+ /* Spill register contents in two passes. First free values that
+ do not reqiure spilling then spill those that do. This approach
+ is only useful in case a stack register contains both kinds of
+ values and the last value is one that does not require spilling.
+ This way we may save one free instruction. */
+ if(IS_STACK_REG(reg))
+ {
+ for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
+ {
+ value = gen->contents[reg].values[index];
+ usage = value_usage(regs, value);
+ if((usage & VALUE_INPUT) == 0
+ && ((usage & VALUE_DEAD) != 0 || value->in_frame))
+ {
+ free_value(gen, value, reg, other_reg);
+ }
+ }
+ }
for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
{
value = gen->contents[reg].values[index];
-
usage = value_usage(regs, value);
- if((usage & VALUE_INPUT) != 0 && (usage & VALUE_USED) == 0)
+ if((usage & VALUE_DEAD) == 0)
{
- continue;
- }
-
- if((usage & VALUE_OUTPUT) == 0)
- {
- if(value->has_global_register)
+ if((usage & VALUE_INPUT) == 0)
{
- if(!value->in_global_register)
- {
- _jit_gen_spill_reg(gen, reg, other_reg, value);
- value->in_global_register = 1;
- }
+ save_value(gen, value, reg, other_reg, 1);
}
else
{
- if(!(value->is_constant || value->in_frame))
- {
- _jit_gen_spill_reg(gen, reg, other_reg, value);
- value->in_frame = 1;
- }
+ save_value(gen, value, reg, other_reg, 0);
}
}
-
- if((usage & VALUE_INPUT) == 0)
+ else
{
- unbind_value(gen, value, reg, other_reg);
+ if((usage & VALUE_INPUT) == 0)
+ {
+ free_value(gen, value, reg, other_reg);
+ }
}
}
}
static void
-adjust_top_value(jit_gencode_t gen, _jit_regs_t *regs, int index, int top, int reg)
+update_age(jit_gencode_t gen, _jit_regdesc_t *desc)
{
- if(regs->descs[index].stack_reg == top)
+ int reg, other_reg;
+
+ reg = desc->value->reg;
+ if(gen->contents[reg].is_long_start)
+ {
+ other_reg = OTHER_REG(reg);
+ }
+ else
{
- regs->descs[index].stack_reg = reg;
+ other_reg = -1;
}
-}
-static void
-adjust_top_values(jit_gencode_t gen, _jit_regs_t *regs, int top, int reg)
-{
- if(regs->ternary)
+ gen->contents[reg].age = gen->current_age;
+ if(other_reg >= 0)
{
- adjust_top_value(gen, regs, 0, top, reg);
+ gen->contents[other_reg].age = gen->current_age;
}
- adjust_top_value(gen, regs, 1, top, reg);
- adjust_top_value(gen, regs, 2, top, reg);
+ ++(gen->current_age);
}
static void
-spill_value(jit_gencode_t gen, _jit_regs_t *regs, jit_value_t value, int reg, int other_reg)
+save_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
{
- int top;
+ _jit_regdesc_t *desc;
+ int reg, other_reg;
#ifdef JIT_REG_DEBUG
- printf("spill_value(value = ");
- jit_dump_value(stdout, jit_value_get_function(value), value, 0);
- printf(", reg = %d, other_reg = %d)\n", reg, other_reg);
+ printf("save_input_value(%d)\n", index);
#endif
- if(IS_STACK_REG(reg))
+ desc = ®s->descs[index];
+ if(!(desc->value && desc->value->in_register && desc->save))
{
- top = get_stack_top(gen, regs->stack_start);
- if(top != reg)
- {
- exch_stack_top(gen, reg, 0);
- adjust_top_values(gen, regs, top, reg);
- }
+ return;
+ }
- if(!(value->is_constant || value->in_frame))
- {
- if(gen->contents[top].num_values == 1)
- {
- _jit_gen_spill_top(gen, top, value, 1);
- }
- else
- {
- _jit_gen_spill_top(gen, top, value, 0);
- }
- value->in_frame = 1;
- }
- else
- {
- if(gen->contents[top].num_values == 1)
- {
- _jit_gen_exch_top(gen, top, 1);
- }
- }
- if(gen->contents[top].num_values == 1)
- {
- remap_stack_down(gen, regs->stack_start, top);
- }
- unbind_value(gen, value, top, -1);
+ reg = desc->value->reg;
+ if(gen->contents[reg].is_long_start)
+ {
+ other_reg = OTHER_REG(reg);
}
else
{
- if(value->has_global_register)
- {
- if(value->global_reg != reg && !value->in_global_register)
- {
- _jit_gen_spill_reg(gen, reg, other_reg, value);
- value->in_global_register = 1;
- }
- }
- else
- {
- if(!value->in_frame)
- {
- _jit_gen_spill_reg(gen, reg, other_reg, value);
- value->in_frame = 1;
- }
- }
- unbind_value(gen, value, reg, other_reg);
+ other_reg = -1;
}
+
+ save_value(gen, desc->value, reg, other_reg, 0);
}
static void
-update_age(jit_gencode_t gen, _jit_regdesc_t *desc)
+free_output_value(jit_gencode_t gen, _jit_regs_t *regs)
{
+ _jit_regdesc_t *desc;
int reg, other_reg;
+#ifdef JIT_REG_DEBUG
+ printf("free_output_value()\n");
+#endif
+
+ desc = ®s->descs[0];
+ if(!(desc->value && desc->value->in_register))
+ {
+ return;
+ }
+ if(desc->value == regs->descs[1].value || desc->value == regs->descs[2].value)
+ {
+ return;
+ }
+
reg = desc->value->reg;
if(gen->contents[reg].is_long_start)
{
other_reg = -1;
}
- gen->contents[reg].age = gen->current_age;
- if(other_reg >= 0)
- {
- gen->contents[other_reg].age = gen->current_age;
- }
- ++(gen->current_age);
+ free_value(gen, desc->value, reg, other_reg);
}
static void
{
_jit_regdesc_t *desc;
+#ifdef JIT_REG_DEBUG
+ printf("load_input_value(%d)\n", index);
+#endif
+
desc = ®s->descs[index];
if(!desc->value || desc->duplicate)
{
_jit_regdesc_t *desc;
int src_reg, dst_reg;
+#ifdef JIT_REG_DEBUG
+ printf("move_input_value(%d)\n", index);
+#endif
+
desc = ®s->descs[index];
if(!desc->value || desc->duplicate || !desc->value->in_register)
{
_jit_regdesc_t *desc;
int reg, other_reg;
+#ifdef JIT_REG_DEBUG
+ printf("commit_input_value(%d)\n", index);
+#endif
+
desc = ®s->descs[index];
- if(!(desc->value && desc->value->in_register))
+ if(!desc->value || desc->duplicate)
{
return;
}
- reg = desc->value->reg;
- if(gen->contents[reg].is_long_start)
- {
- other_reg = OTHER_REG(reg);
- }
- else
+ if(desc->copy)
{
- other_reg = -1;
+ if(IS_STACK_REG(desc->reg))
+ {
+ remap_stack_down(gen, regs->stack_start, desc->reg);
+ }
+ gen->contents[desc->reg].used_for_temp = 0;
+ if(desc->other_reg >= 0)
+ {
+ gen->contents[desc->other_reg].used_for_temp = 0;
+ }
}
- /* If the value is clobbered then it must have been spilled
- before the operation. Simply unbind it here. */
- if(jit_reg_is_used(regs->clobber, reg)
- || (other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg)))
+ if(desc->kill && desc->value->in_register)
{
- if(IS_STACK_REG(reg))
+ reg = desc->value->reg;
+ if(gen->contents[reg].is_long_start)
{
- unbind_value(gen, desc->value, reg, -1);
- remap_stack_down(gen, regs->stack_start, reg);
+ other_reg = OTHER_REG(reg);
}
else
{
- unbind_value(gen, desc->value, reg, other_reg);
-#if 0
- if(!(jit_reg_is_used(regs->clobber, desc->reg)
- || (desc->other_reg >= 0
- && jit_reg_is_used(regs->clobber, desc->other_reg))))
- {
- bind_value(gen, desc->value, desc->reg, desc->other_reg, 1);
- }
-#endif
+ other_reg = -1;
}
- return;
- }
- if(!desc->used)
- {
- if(desc->live || (IS_STACK_REG(reg) && gen->contents[reg].num_values == 1))
+ if(IS_STACK_REG(reg))
{
- spill_value(gen, regs, desc->value, reg, other_reg);
+ unbind_value(gen, desc->value, reg, -1);
+ remap_stack_down(gen, regs->stack_start, reg);
}
else
{
unbind_value(gen, desc->value, reg, other_reg);
}
}
+
+#ifdef JIT_REG_DEBUG
+ printf("value = ");
+ jit_dump_value(stdout, jit_value_get_function(desc->value), desc->value, 0);
+ printf("\n");
+ printf("value->in_register = %d\n", desc->value->in_register);
+ printf("value->reg = %d\n", desc->value->reg);
+ printf("value->in_gloable_register = %d\n", desc->value->in_global_register);
+ printf("value->in_frame = %d\n", desc->value->in_frame);
+#endif
}
static void
commit_output_value(jit_gencode_t gen, _jit_regs_t *regs)
{
_jit_regdesc_t *desc;
- int reg, other_reg;
+
+#ifdef JIT_REG_DEBUG
+ printf("commit_output_value()\n");
+#endif
desc = ®s->descs[0];
if(!desc->value)
return;
}
- if(desc->value->in_register)
+ if(IS_STACK_REG(desc->reg))
{
- reg = desc->value->reg;
- if(gen->contents[reg].is_long_start)
- {
- other_reg = OTHER_REG(reg);
- }
- else
- {
- other_reg = -1;
- }
- unbind_value(gen, desc->value, reg, other_reg);
+ bind_value(gen, desc->value, desc->reg, -1, 0);
+ remap_stack_up(gen, regs->stack_start, desc->reg);
}
- if(desc->used || desc->live || IS_STACK_REG(desc->reg))
+ else
{
- if(IS_STACK_REG(desc->reg))
+ bind_value(gen, desc->value, desc->reg, desc->other_reg, 0);
+ }
+ if(!desc->used)
+ {
+ if(desc->live)
{
- bind_value(gen, desc->value, desc->reg, -1, 0);
- remap_stack_up(gen, regs->stack_start, desc->reg);
+ save_value(gen, desc->value, desc->reg, desc->other_reg, 1);
}
else
{
- bind_value(gen, desc->value, desc->reg, desc->other_reg, 0);
- }
- if(!desc->used)
- {
- if(desc->live || IS_STACK_REG(desc->reg))
- {
- spill_value(gen, regs, desc->value, desc->reg, desc->other_reg);
- }
- else
- {
- unbind_value(gen, desc->value, desc->reg, desc->other_reg);
- }
+ free_value(gen, desc->value, desc->reg, desc->other_reg);
}
}
+
+#ifdef JIT_REG_DEBUG
+ printf("value = ");
+ jit_dump_value(stdout, jit_value_get_function(desc->value), desc->value, 0);
+ printf("\n");
+ printf("value->in_register = %d\n", desc->value->in_register);
+ printf("value->reg = %d\n", desc->value->reg);
+ printf("value->in_gloable_register = %d\n", desc->value->in_global_register);
+ printf("value->in_frame = %d\n", desc->value->in_frame);
+#endif
}
void
regs->spill = jit_regused_init;
regs->stack_start = -1;
- regs->initial_stack_top = 0;
regs->current_stack_top = 0;
regs->wanted_stack_count = 0;
regs->loaded_stack_count = 0;
- regs->num_exchanges = 0;
}
void
int index, out_index;
#ifdef JIT_REG_DEBUG
- dump_regs(gen, "enter _jit_regs_assign");
+ printf("_jit_regs_assign()\n");
#endif
/* Set clobber flags. */
{
jit_reg_set_used(regs->clobber, index);
}
+#if 0
if(jit_reg_is_used(regs->clobber, index))
{
jit_reg_set_used(gen->touched, index);
}
+#endif
}
/* Spill all clobbered registers. */
{
return 0;
}
- set_register_flags(gen, regs, regs->scratch[index].reg, 1, 0);
}
}
{
if(regs->descs[out_index].value->in_register
&& gen->contents[regs->descs[out_index].value->reg].num_values == 1
- && !(regs->descs[out_index].live || regs->descs[out_index].used))
+ && !(/*regs->descs[out_index].live ||*/regs->descs[out_index].used))
{
+ /* NOTE: The last condition makes sense for local register
+ allocation, review it for future global allocator. */
use_cheapest_register(
gen, regs, out_index, regs->descs[out_index].regset);
if(regs->descs[out_index].reg < 0)
{
return 0;
}
- set_register_flags(gen, regs, regs->scratch[index].reg, 1, 0);
}
}
/* Collect information about registers. */
- if(!collect_register_info(regs, 0))
+ if(!collect_register_info(gen, regs, 0))
{
return 0;
}
- if(!collect_register_info(regs, 1))
+ if(!collect_register_info(gen, regs, 1))
{
return 0;
}
- if(!collect_register_info(regs, 2))
+ if(!collect_register_info(gen, regs, 2))
{
return 0;
}
-#ifdef JIT_REG_DEBUG
- dump_regs(gen, "leave _jit_regs_assign");
-#endif
return 1;
}
dump_regs(gen, "enter _jit_regs_gen");
#endif
- /* Remember initial stack size. */
- if(regs->wanted_stack_count > 0)
- {
- regs->initial_stack_top = get_stack_top(gen, regs->stack_start);
- }
-
/* Spill clobbered registers. */
stack_start = 0;
for(reg = 0; reg < JIT_NUM_REGS; reg++)
As we spill each one, something else will become the top */
if(IS_STACK_REG(reg))
{
- top = gen->stack_map[stack_start];
+ top = get_stack_top(gen, stack_start);
while(top > reg && jit_reg_is_used(regs->spill, top))
{
- spill_stack_top(gen, regs, stack_start);
+ spill_reg(gen, regs, top);
+ /* If one of the input values is on the top
+ spill_reg() will not pop it. */
if(gen->contents[top].num_values > 0)
{
- /* If one of the input values is on the top
- spill_stack_top() does not pop it. */
break;
}
- top = gen->stack_map[stack_start];
+ top = get_stack_top(gen, stack_start);
}
if(top > reg)
{
exch_stack_top(gen, reg, 0);
- if(regs->num_exchanges >= _JIT_REGS_MAX_EXCHANGES)
- {
- return 0;
- }
- regs->exchanges[regs->num_exchanges][0] = top;
- regs->exchanges[regs->num_exchanges][1] = reg;
- ++(regs->num_exchanges);
-
- if(jit_reg_is_used(regs->spill, top))
- {
- jit_reg_set_used(regs->spill, reg);
- }
- else
- {
- jit_reg_clear_used(regs->spill, reg);
- }
- jit_reg_set_used(regs->spill, top);
}
- spill_stack_top(gen, regs, stack_start);
+ if(top >= stack_start)
+ {
+ spill_reg(gen, regs, top);
+ }
}
else
{
}
}
+ /* Save input values if necessary and free output value if it is in a register */
+ if(regs->ternary)
+ {
+ save_input_value(gen, regs, 0);
+ }
+ else
+ {
+ free_output_value(gen, regs);
+ }
+ save_input_value(gen, regs, 1);
+ save_input_value(gen, regs, 2);
+
/* Adjust assignment of stack registers. */
if(regs->wanted_stack_count > 0)
{